老刘是一名即将找工作的研二学生,写博客一方面是复习总结大数据开发的知识点,一方面是希望能够帮助和自己一样自学编程的伙伴。由于老刘是自学大数据开发,博客中肯定会存在一些不足,还希望大家能够批评指正,让我们一起进步!
今天给各位小伙伴聊聊分布式系统的数据一致性问题,这个一定要从服务器架构部署的发展历程讲起!文章篇幅较长,请大家耐心观看,精彩千万不要错过!
首先要讲的是集中式服务,那集中式是什么?就是事情都由一台服务器搞定。
而集中式系统就是由一台或多台主计算机组成中心节点,数据集中存储于这个中心节点中,并且整个系统的所有业务都在这个中心节点上,系统所有的功能都由它做。
也就是说,在集中式系统中,每个客户端仅仅负责数据的输入和输出,而数据的存储与控制处理完全交给主机完成。
那集中式服务优点:
但是它的缺点也是非常明显:
什么是摩尔定律?
摩尔定律是由英特尔(Intel)创始人之一戈登·摩尔(Gordon Moore)提出来的。其内容为:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。摘自:百度百科
摩尔定律告诉我们:纵向扩展理论上是受限的,所以只能考虑横向扩展,而且从理论上说,横向扩展理论上是不受限的!
那既然纵向扩展受限,我们就去尝试横向扩展,就有了分布式!
分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。计算机越多,CPU、内存、存储资源等也就越多,能够处理的并发访问量也就越大。
例如一个由分布式系统实现的电子商城,在功能上可能被拆分成多个应用,分别提供不同的功能,组成一个分布式系统对外提供服务。
所以,分布式系统中的计算机在空间上是几乎没有限制的,这些计算机可能被放在不同的机柜上,也可能被部署在不同的机房中,还可能在不同的城市中。
和集中式系统相比,分布式系统的性价比更高、处理能力更强、可靠性更高、也有很好的扩展性。
但是,分布式解决了网站的高并发问题的同时也带来了一些其他问题。
首先,分布式的必要条件就是网络,这可能对性能甚至服务能力造成一定的影响。其次,一个集群中的服务器数量越多,服务器宕机的概率也就越大。另外,由于服务在集群中分布式部署,用户的请求只会落到其中一台机器上,所以,一旦处理不好就很容易产生数据一致性问题。
1、通信异常:网络不可用(消息延迟或者丢失),会导致分布式系统内部无法顺利进行网络通信,所以可能造成多个节点数据丢失和状态不一致,还有可能造成数据乱序。
2、网络分区:网络不连通,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成若干个孤立的区域,分布式系统就出现了局部小集群造成的数据不一致。
3、节点故障:服务器节点出现的宕机的现象。
4、存储数据丢失:对于有状态节点来说,数据丢失意味着状态丢失,通常只能从其他节点读取、恢复存储的状态。解决方案:利用多副本机制。
1、性能:这是一个非常让人头疼的问题,追求高吞吐的系统,往往很难做到低延迟;系统平均响应时间较长时,也很难提高QPS。
系统的吞吐能力,指系统在某一时间可以处理的数据总量,通常可以用系统每秒处理的总数据量来衡量; 系统的响应延迟,指系统完成某一功能需要使用的时间; 系统的并发能力,指系统可以同时完成某一功能的能力,通常也用QPS来衡量。
2、可用性:系统的可用性(availability)指系统在面对各种异常时可以正确提供服务的能力。可用性是分布式的重要指标,衡量了系统的鲁棒性,是系统容错能力的体现。
3、可扩展性:系统的可扩展性(scalability)指分布式系统通过扩展集群机器规模提高系统性能(吞吐、延迟、并发)、存储容量、计算能力的特性。
4、一致性:分布式系统为了提高可用性,总是不可避免地使用副本的机制,从而引发副本一致性的问题。
例如,就是一份数据存在分布式系统,存在多个不同的节点当中存着相同的数据。如果多个不同的节点存的数据不一样,多个客户端去访问的时候就会存在这种情况,第1个客户端去访问的结果为A,第2个客户端访问的结果为B,两个客户端访问得到不同的结果,那就是一致性做的不好。
说了这么多,我们如果设计一个优秀的分布式系统,它应该具有这些特点:吞吐高、响应延迟低、并发强、可用性很高、可扩展性很强、一致性很好。但并不是每个特点都能满足,有几个特点是相互矛盾的,需要我们想办法克服!
而在分布式场景中真正复杂的是数据一致性的问题!
一致性也分很多种,这里说说老刘了解的三个。
强一致性:写操作完成之后,读操作一定能读到最新数据。通俗地讲就是客户端只要把结果写进去了,什么时候访问都能拿到最新的数据。但是在分布式场景中很难实现,后续的Paxos 算法,Quorum 机制,ZAB 协议等能实现!
弱一致性:不保证拿到最新的数据,也有可能拿到旧的数据。
最终一致性:不考虑中间的任何状态,只保证经过一段时间之后,最终系统内数据正确。在高并发场景中,它也是使用最广的一致性模型。
说了那么多分布式一致性的内容,那它的作用是什么呢?
1、为了提高系统的可用性,一般都会使用多副本机制,多副本就会有分布式一致性的问题,它就是为了提高系统的可用性,防止单点节点故障引起的系统不可用。
2、提高系统的整体性能,数据分布在集群中多个节点上,它们都能为用户提供服务。
老刘说了这么多,大家有没有猜到想引出什么内容呢?
上述那么多内容只为引出分布式系统的数据一致性问题!我们用来解决分布式系统的数据一致性问题的方案有如下:
分布式事务+事务 分布式一致性算法 Quorum机制 CAP和BASE理论
分布式系统中,每个节点都能知道自己的事务操作是否成功,但是没法知道系统中的其他节点的事务是否成功。这就有可能会造成分布式系统中的各节点的状态出现不一致。因此当一个事务需要跨越服务器节点,并且要保证事务的ACID特性时,就必须引入一个协调者的角色。那么其他的各个进行事务操作的节点就都叫做参与者。
现实生活中有两种典型的分布式事务的提交模式:2PC和3PC。
直接上图:
我让A去做一件事,让B去做另外一件事,并且这两件事在一个分布式事务中要保证同时成功或失败。那如何做到数据一致呢?
2PC分两个阶段: 第一阶段:执行事务,但不提交。 第二阶段:当协调者收到第一阶段中所有事务参与者的正反馈时(事务都执行成功了), 就去发命令让所有参与者提交事务。
看了2PC的两个提交阶段和图,有经验的人一眼就会看出里面存在的问题。
1 阻塞问题
协调者发送命令给参与者,由于是网路发送命令,就会存在不同参与者收到的命令有先后、有延迟。例如参与者A很快就收到了,参与者B网络有问题,过了很久才收到命令。参与者A很快处理完发送反馈, 而参与者B就很久之后才发送反馈,导致协调者等待时间特别长。 这就是一个非常典型的阻塞问题,非常浪费资源,影响性能!
2 没有容错机制,存在单点故障问题
事务协调者是整个分布式事务的核心,一旦协调者出现故障,看看上面那张图,就会知道参与者就收不到 commit/rollback的通知,从而导致参与者节点一直处于事务无法完成的中间状态。
3 数据不一致
在第二阶段,如果发生局部网络问题,一个参与者收到提交的命令,另一个参与者没有收到提交的命令, 就会造成节点间数据不一致。
3PC就是三阶段提交的意思,它是2阶段提交的改进版,把二阶段提交协议的 "提交事务请求" 一分为二,形成了cancommit,precommit,docommit 三个阶段。
除了在 2PC 的基础上增加了CanCommit阶段,还引入了超时机制。一旦事务参与者在指定时间内没有收到协调者的 commit/rollback 指令,就会自动本地 commit,这样可以解决协调者单点故障的问题。
第一阶段:CanCommit阶段
在第一阶段准备的时候,先问一下各个参与者是否可以进行事务操作以及超时机制,参与者在一定时间没 收到协调者的指令会自动提交。
第二阶段:PreCommit阶段
1、如果每个参与者返回的都是同意,协调者则向所有参与者发送预提交请求,并进入预提交阶段; 2、参与者收到预提交请求后,执行事务操作。 3、参与者执行完本地事务之后,会向协调者发出Ack表示已准备好提交,并等待协调者下一步指令。 4、如果协调者收到预提交响应为拒绝或者超时,则执行中断事务操作,通知各参与者中断事务。 5、参与者收到中断事务或者等待超时,都会主动中断事务/直接提交
第三阶段:doCommit阶段
1、协调者收到所有参与 的Ack,则从预提交入提交段,并向各参与者发送提交请求。 2、参与者收到提交请求,正式提交事务(commit),并向协调者反馈提交结果Y/N。 3、协调者收到所有反馈消息,完成分布式事务。 4、如果协调者超时没有收到反馈,则发送中断事务指令。 5、参与者收到中断事务指令后,利用事务日志进行rollback。 6、参与者反馈回滚结果,协调者接收反馈结果或者超时,完成中断事务。
3PC也可能出现数据不一致,第三阶段让所有参与者回滚事务,但有一个参与者在规定的时间内没有收到,它会默认进行提交操作,就会出现数据不一致。由于网络问题,第二阶段到第三阶段之间特别容易出现数据不一致问题。
在2PC和3PC的原理上,优秀的开发者们实现了分布式一致性算法,这里老刘先大致讲讲Poxos算法和ZAB协议的相关概念。如果想详细了解Paxos算法和ZAB协议,等老刘找完工作后,专门写一篇Zookeeper源码文章。
Paxos 算法使用一个希腊故事来描述,在 Paxos 中,存在三种角色,分别为
1、Proposer(提议者,用来发出提案proposal), 2、Acceptor(接受者,可以接受或拒绝提案), 3、Learner(学习者,学习被选定的提案,当提案被超过半数的Acceptor接受后为被批准)。
映射到 zookeeper 集群:
leader:发起提案 主席(单点故障的解决办法是leader选举机制) follower:参与投票 人大代表 observer:被动接受 全国所有人
以及有一个特别出名的机制:议会制
保证超过半数达成一致性即可的协议
总结下Paxos算法,它就是所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 leader 服务器,而余下的其他服务器则成为 follower 服务器。
leader 服务器负责将一个客户端事务请求转换成一个事务proposal,并将该 proposal 分发给集群中所有的follower 服务器。之后 leader 服务器需要等待所有follower 服务器的反馈,一旦超过半数的 follower 服务器进行了正确的反馈后,那么 leader 就会再次向所有的 follower 服务器分发 commit 消息,要求其将前一个 proposal 进行提交。
ZooKeeper的底层工作机制,就是依靠 ZAB 实现的。它实现了崩溃回复和消息广播两个主要功能。
ZAB协议保证数据一致性的两个重要特点就是:
1、ZAB协议需要确保那些已经在 leader 服务器上提交的事务最终被所有服务器都提交。
2、ZAB协议需要确保丢弃那些只在 leader 服务器上被提出的事务。
为了解决单点故障,有leader选举算法。在leader选举中,如果让 leader 选举算法能够保证新选举出来的 leader 服务器拥有集群中所有机器最高事务编号(ZXID)的事务proposal,那么就可以保证这个新选举出来的 leader 一定具有所有已经提交的提案。
因为事务的每次执行都会有一个编号,最高事务编号代表着最新的事务,即最新的数据。 根据上述ZAB协议内容,ZooKeeper实现了分布式系统数据的一致性!
简单描述:若有n个笼子和n+1只鸽子,所有的鸽子都被关在鸽笼里,那么至少有一个笼子有至少2只鸽子 。
Quorum NWR:Quorum 机制是分布式场景中常用的,用来保证数据安全,并且在分布式环境中实现最终一致性的投票算法。这种算法的主要原理来源于鸽巢原理。它最大的优势,既能实现强一致性,而且还能自定义一致性级别!
N:总节点数
W:总写入成功数
R:总读取数
当W+R>N时,一定能保证读到最新的数据,即强一致性! 为什么这样说?
如上图,有4个箱子,3个箱子里面有东西,那如何保证一定能拿到有数据的箱子?最起码拿2个箱子就能拿到有东西的箱子!
就是利用这种原理,只要保证(W + R > N)就一定能读取到最新的数据,数据一致性级别完全可以根据读写副本数的约束来达到强一致性!
那现在分以下三种情况讨论:前提是N已经确定不改了!
W = 1, R = N,Write Once Read All
在分布式环境中,写一份,相当于只有只有一个箱子有东西,那么如果要读取到最新数据,即拿到有东西的箱子,就必须要读取所有节点,然后取最新版本的值了。写操作高效,但是读操作效率低。一致性高,但分区容错性差,可用性低。
W = N,R = 1, Read Only Write All
在分布式环境中,所有节点都同步完毕,才能读取,所以只要读取任意一个节点就可以读取到最新数据。读操作高效,但是写操作效率低。分区容错性好,一致性差,实现难度更高,可用性高 。
W = Q, R = Q where Q = N/2 + 1
可以简单理解为写超过一半节点,那么读也超过一半节点,取得读写性能平衡。一般应用适用,读写性能之间取得平衡。如 N=3, W=2, R=2,分区容错性,可用性,一致性取得一个平衡。
ZooKeeper就是这么干的!采用了第三种情况!
根据上述说的,做到强一致性了,就难做到高可用,两者是非常矛盾的。所以CAP理论就告诉我们,一个分布式系统不可能同时满足C,A,P三个需求。
C:Consistency,强一致性
分布式环境中多个数据副本保持一致
A:Availability,高可用性
系统提供的服务必须一直处于可用,对于用户的每一个操作请求总是能在有限时间内返回结果
P:Partiton Tolerance 分区容错性
分布式系统在遇到任何网络分区故障时,仍然需要能够保证对外提供满足一致性和可用性的服务
既然一个分布式系统不能同时满足C,A,P三个需求,那么如何选择?
CAP只能3选2,因为在分布式系统中,容错性P肯定是必须有的,所以这时候无非就两种情况,网络问题导致要么错误返回,要么阻塞等待,前者牺牲了一致性,后者牺牲了可用性。
对于单机软件,因为不同考虑P,所以肯定是CA型,比如MySQL。
对于分布式软件,因为一定会考虑P,所以又不能兼顾A和C的情况下,只能在A和C做权衡,比如HBase、Redis等。做到服务基本可用,并且数据最终一致性即可。 所以,就产生了BASE理论。
多数情况下,其实我们也并非一定要求强一致性,部分业务可以容忍一定程度的延迟一致,所以为了兼顾效率,发展出来了最终一致性理论 BASE,它的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
一句话就是做事别走极端,BASE 是对 CAP 理论中的 C 和 A 进行权衡得到的结果。
BASE理论做到的不是强一致,而是最终一致;不是高可用,而是基本可用。
Basically Available(基本可用):基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。 例如:淘宝双11,为保护系统稳定性,正常下单,其他边缘服务可暂时不可用。
Eventually Consistent(最终一致):最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。
以后开发分布式系统,就可以根据业务来决定到底追求高可用还是追求强一致性!
好啦,分布式系统的数据一致性问题大致聊得差不多了,老刘主要给大家讲了讲分布式系统一致性的背景以及实现。尽管当前水平可能不及各位大佬,但老刘还是希望能够变得更加优秀,能够帮助更多自学编程的伙伴。
如果有相关问题,请联系公众号:努力的老刘,和老刘进行愉快的交流,如果觉得帮到了您,不妨点赞关注支持一波!