读写分离

为了确保数据库产品的稳定性,很多数据库拥有双机热备功能。也就是,第一台数据库服务器,是对外提供增删改业务的生产服务器;第二台数据库服务器,主要进行读的操作。

原 理:让主数据库处理事务性增、改、删操作,而从数据库处理SELECT查询操作

第一台数据库服务器,是对外提供增删改查业务的生产服务器;第二台数据库服务器,仅仅接收来自第一台服务器的备份数据(注意,不同数据库产品,第一台数据库服务器,向第二台数据库服务器发送备份数据的方式不同)。当第一台数据库崩溃后,第二台数据库服务器,可以立即上线来代替第一台数据库服务器,并且,在第一台数据库服务器崩溃后,宝贵的数据,依然会存在于第二台数据库服务器里(根据目前业界的备份数据发送方式来看,当第一台数据库崩溃后,第一台数据库里的仍然会有少量的新数据,没能来得及被发送到第二台数据库服务器,所以,这部分数据就丢失了)。

现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。

  采用读写分离技术的目标:有效减轻Master库的压力,又可以把用户查询数据的请求分发到不同的Slave库,从而保证系统的健壮性。我们看下采用读写分离的背景。

  随着网站的业务不断扩展,数据不断增加,用户越来越多,数据库的压力也就越来越大,采用传统的方式,比如:数据库或者SQL的优化基本已达不到要求,这个时候可以采用读写分离的策 略来改变现状。

  具体到开发中,如何方便的实现读写分离呢?目前常用的有两种方式:

  1 第一种方式是我们最常用的方式,就是定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时我们读取MasterDataSource,查询数据时我们读取SlaveDataSource。这种方式很简单,我就不赘述了。

  2 第二种方式动态数据源切换,就是在程序运行时,把数据源动态织入到程序中,从而选择读取主库还是从库。主要使用的技术是:annotation,Spring AOP ,反射。下面会详细的介绍实现方式。

   在介绍实现方式之前,我们先准备一些必要的知识,spring 的AbstractRoutingDataSource 类

     AbstractRoutingDataSource这个类 是spring2.0以后增加的,我们先来看下AbstractRoutingDataSource的定义:

    public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean  {}

本文转载http://www.cnblogs.com/surge/p/3582248.html 感谢作者

先对上一篇比较erlang与go语言的话题作一个补充,我的一个架构师同事写了一段简单的累加代码测试erlang密集计算的性能,测下来erlang的计算性能大概是c#的1/10,这个符合我的预期,动态类型语言和静态类型语言的性能,差不多就是差10倍,所以,go语言还是大有可为的(go语言比python快15倍)。

我经常喜欢和朋友聊软件技术的话题,如果觉得还有点意思,怕自己忘记,就应该记下来,就像我现在正在做的,人就是在自我否定中前行,所以我说的,有可能都是错的。

我的架构师同事问我:“为什么你总说要在服务层实现读写分离,我们已经在数据库实现了读写分离,是不是已经够用”。以下是我的解释,

在做网站性能优化的时候,我常常忘记还有数据库读写分离这件事,因为数据库读写分离,对性能带来的提高太有限了,实际上,就是一倍(一台服务器变成两台服务器)。当你的网站业务发展,如果从无到有地使用数据库读写分离,提高了一倍的服务能力,你很快就需要想新的优化方案。实际上,数据库的读写分离,更像是数据安全的一个副产品,用一台数据库服务器不安全(怕数据丢失),用一台服务器作为备份,既然有了两台服务器,就充分利用吧,于是有了“读写分离”,提高一倍也是好的。

于是,能够十倍百倍提高性能的方案出现了,缓存加服务器集群,这是最常用且有效的提高网站访问量的设计。使用共享缓存(memcached,redis)可以获得十到几十倍的性能提升,使用进程内缓存,可以得到百倍的性能提升;集群中增加一倍的服务器,可以增加一倍的计算能力,服务更多的并发请求。等一下,上面所说的方案,其实只对“读”操作才有效,对“写”操作可以说是毫无用处。

那么有什么办法可以提高“写”操作的性能,在架构部署的设计方面,我的答案是,“没有”。

从硬件入手,可以使用SSD硬盘。愿意替换底层数据库,可以使用hbase或者cassandra,都不在今天讨论的范围。我想说的是,既然使用缓存和增加服务器,对于“写”操作没有优化作用,在一开始,“写”操作相关的服务,就不该和“读”操作一起,被分配到数量庞大的计算机集群里。

想象这样的架构设计,我有一个“读”服务的集群,一共4台服务器,我有一台“写”服务器(另一台备用,故障时切换)。当我的网站访问量上升,我增加“读”服务器集群到8台,简单就能应付问题。因为“读”服务是状态无关的,增加到100台也不会带来错误的数据,这是一个重要的思想,状态无关的服务,才可以放心地水平扩展,事实上,状态无关的服务,通常只有“读”服务。

那么当“写”服务撑不住的时候,怎么办,嗯。。。总会有办法,反正不是加缓存或者是使用集群,这个可以做架构师面试题。

然后我解释一下为什么不该在集群里面运行“写”服务,我把“写”服务分为两种。

1.       和“状态”(可能发生冲突的情形)弱相关,比如用户提供内容(UGC)的操作,每个用户提交自己的评论,或者发布自己的微博,不太容易发生冲突。对于这类“写”服务,部署在集群里面勉强可行,虽然没带来什么好处,但也没有引入错误

2.       和“状态”(可能发生冲突的情形)强相关,比如包含库存操作的电商网站,上千人“秒杀”热门商品,允许这样的操作在集群内并发,是架构师自己作死的节奏啊

明白了这个道理,你就知道我之前为什么说是“一台”写服务器,只有一台服务器,才可以保证在“秒杀”场景下,不会在没有库存的情况下继续售卖成功。

细心的读者(嗯,就是你)会继续追问,在一台服务器的情况下,现在都是多核并发编程,保证串行操作也不是容易的事啊。问得太好了,我这大半年写的系列文章,都是为了解决这个问题,你需要的是actor模型。异步编程加上进程内的消息队列,可以高效地对并发操作进行串行的处理。

结论,使用服务器集群提高性能只对“读”服务有效,对“写”服务无效,“写”服务器应该使用主/从模式,同一时间只使用一台服务器。在“写”服务器内部,使用支持actor模型的编程语言,保证关键操作的串行。最后老生常谈,支持actor模型的编程语言是:Erlang,Go,Scala,F#

原文地址:https://www.cnblogs.com/panxuejun/p/5938595.html