今天给各位小伙伴聊聊分布式系统的数据一致性问题,这个一定要从服务器架构部署的发展历程讲起!文章篇幅较长,请大家耐心观看,精彩千万不要错过!

1. 背景

1.1. 集中式服务

首先要讲的是集中式服务,那集中式是什么?就是事情都由一台服务器搞定。

而集中式系统就是由一台或多台主计算机组成中心节点,数据集中存储于这个中心节点中,并且整个系统的所有业务都在这个中心节点上,系统所有的功能都由它做。

也就是说,在集中式系统中,每个客户端仅仅负责数据的输入和输出,而数据的存储与控制处理完全交给主机完成。

带你了解分布式系统的数据一致性问题-LMLPHP

那集中式服务优点:

  1. 结构简单
  2. 部署简单
  3. 项目架构简单

但是它的缺点也是非常明显:

  1. 大型主机的研发和维护成本非常高
  2. 大型主机非常昂贵
  3. 存在单点故障问题,主机一挂,所有服务终止
  4. 大型主机的性能扩展受限于摩尔定律

什么是摩尔定律?

摩尔定律是由英特尔(Intel)创始人之一戈登·摩尔(Gordon Moore)提出来的。其内容为:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。摘自:百度百科

摩尔定律告诉我们:纵向扩展理论上是受限的,所以只能考虑横向扩展,而且从理论上说,横向扩展理论上是不受限的!

那既然纵向扩展受限,我们就去尝试横向扩展,就有了分布式!

1.2. 分布式服务

分布式意味着可以采用更多的普通计算机(相对于昂贵的大型机)组成分布式集群对外提供服务。计算机越多,CPU、内存、存储资源等也就越多,能够处理的并发访问量也就越大。

例如一个由分布式系统实现的电子商城,在功能上可能被拆分成多个应用,分别提供不同的功能,组成一个分布式系统对外提供服务。

所以,分布式系统中的计算机在空间上是几乎没有限制的,这些计算机可能被放在不同的机柜上,也可能被部署在不同的机房中,还可能在不同的城市中。

带你了解分布式系统的数据一致性问题-LMLPHP

和集中式系统相比,分布式系统的性价比更高、处理能力更强、可靠性更高、也有很好的扩展性。

但是,分布式解决了网站的高并发问题的同时也带来了一些其他问题。

首先,分布式的必要条件就是网络,这可能对性能甚至服务能力造成一定的影响。其次,一个集群中的服务器数量越多,服务器宕机的概率也就越大。另外,由于服务在集群中分布式部署,用户的请求只会落到其中一台机器上,所以,一旦处理不好就很容易产生数据一致性问题。

1.3. 分布式存在的异常

1、通信异常:网络不可用(消息延迟或者丢失),会导致分布式系统内部无法顺利进行网络通信,所以可能造成多个节点数据丢失和状态不一致,还有可能造成数据乱序。

2、网络分区:网络不连通,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成若干个孤立的区域,分布式系统就出现了局部小集群造成的数据不一致。

3、节点故障:服务器节点出现的宕机的现象。

4、存储数据丢失:对于有状态节点来说,数据丢失意味着状态丢失,通常只能从其他节点读取、恢复存储的状态。解决方案:利用多副本机制。

1.4. 衡量分布式系统的性能指标

1、性能:这是一个非常让人头疼的问题,追求高吞吐的系统,往往很难做到低延迟;系统平均响应时间较长时,也很难提高QPS。

2、可用性:系统的可用性(availability)指系统在面对各种异常时可以正确提供服务的能力。可用性是分布式的重要指标,衡量了系统的鲁棒性,是系统容错能力的体现。

3、可扩展性:系统的可扩展性(scalability)指分布式系统通过扩展集群机器规模提高系统性能(吞吐、延迟、并发)、存储容量、计算能力的特性。

4、一致性:分布式系统为了提高可用性,总是不可避免地使用副本的机制,从而引发副本一致性的问题。

例如,就是一份数据存在分布式系统,存在多个不同的节点当中存着相同的数据。如果多个不同的节点存的数据不一样,多个客户端去访问的时候就会存在这种情况,第1个客户端去访问的结果为A,第2个客户端访问的结果为B,两个客户端访问得到不同的结果,那就是一致性做的不好。

说了这么多,我们如果设计一个优秀的分布式系统,它应该具有这些特点:吞吐高、响应延迟低、并发强、可用性很高、可扩展性很强、一致性很好。但并不是每个特点都能满足,有几个特点是相互矛盾的,需要我们想办法克服!

而在分布式场景中真正复杂的是数据一致性的问题!

1.5. 一致性理解

一致性也分很多种,这里说说老刘了解的三个。

强一致性:写操作完成之后,读操作一定能读到最新数据。通俗地讲就是客户端只要把结果写进去了,什么时候访问都能拿到最新的数据。但是在分布式场景中很难实现,后续的Paxos 算法,Quorum 机制,ZAB 协议等能实现!

弱一致性:不保证拿到最新的数据,也有可能拿到旧的数据。

最终一致性:不考虑中间的任何状态,只保证经过一段时间之后,最终系统内数据正确。在高并发场景中,它也是使用最广的一致性模型。

1.6. 分布式一致性的作用

说了那么多分布式一致性的内容,那它的作用是什么呢?

1、为了提高系统的可用性,一般都会使用多副本机制,多副本就会有分布式一致性的问题,它就是为了提高系统的可用性,防止单点节点故障引起的系统不可用。

2、提高系统的整体性能,数据分布在集群中多个节点上,它们都能为用户提供服务。

老刘说了这么多,大家有没有猜到想引出什么内容呢?

上述那么多内容只为引出分布式系统的数据一致性问题!我们用来解决分布式系统的数据一致性问题的方案有如下:

2. 分布式事务

分布式系统中,每个节点都能知道自己的事务操作是否成功,但是没法知道系统中的其他节点的事务是否成功。这就有可能会造成分布式系统中的各节点的状态出现不一致。因此当一个事务需要跨越服务器节点,并且要保证事务的ACID特性时,就必须引入一个协调者的角色。那么其他的各个进行事务操作的节点就都叫做参与者。

现实生活中有两种典型的分布式事务的提交模式:2PC和3PC。

2.1. 2PC提交过程

直接上图:

带你了解分布式系统的数据一致性问题-LMLPHP

我让A去做一件事,让B去做另外一件事,并且这两件事在一个分布式事务中要保证同时成功或失败。那如何做到数据一致呢?

 

2.2. 2PC的问题

看了2PC的两个提交阶段和图,有经验的人一眼就会看出里面存在的问题。

1 阻塞问题

2 没有容错机制,存在单点故障问题

3 数据不一致

2.3. 3PC

3PC就是三阶段提交的意思,它是2阶段提交的改进版,把二阶段提交协议的 "提交事务请求" 一分为二,形成了cancommit,precommit,docommit 三个阶段。

除了在 2PC 的基础上增加了CanCommit阶段,还引入了超时机制。一旦事务参与者在指定时间内没有收到协调者的 commit/rollback 指令,就会自动本地 commit,这样可以解决协调者单点故障的问题。

2.4. 执行过程解析

第一阶段:CanCommit阶段

第二阶段:PreCommit阶段

第三阶段:doCommit阶段

2.5. 3PC的问题

3PC也可能出现数据不一致,第三阶段让所有参与者回滚事务,但有一个参与者在规定的时间内没有收到,它会默认进行提交操作,就会出现数据不一致。由于网络问题,第二阶段到第三阶段之间特别容易出现数据不一致问题。

3. 分布式一致性算法

在2PC和3PC的原理上,优秀的开发者们实现了分布式一致性算法,这里老刘先大致讲讲Poxos算法和ZAB协议的相关概念。如果想详细了解Paxos算法和ZAB协议,等老刘找完工作后,专门写一篇Zookeeper源码文章。

3.1. Paxos算法

Paxos 算法使用一个希腊故事来描述,在 Paxos 中,存在三种角色,分别为

映射到 zookeeper 集群:

以及有一个特别出名的机制:议会制

总结下Paxos算法,它就是所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为 leader 服务器,而余下的其他服务器则成为 follower 服务器。

leader 服务器负责将一个客户端事务请求转换成一个事务proposal,并将该 proposal 分发给集群中所有的follower 服务器。之后 leader 服务器需要等待所有follower 服务器的反馈,一旦超过半数的 follower 服务器进行了正确的反馈后,那么 leader 就会再次向所有的 follower 服务器分发 commit 消息,要求其将前一个 proposal 进行提交。

3.2. ZAB协议

ZooKeeper的底层工作机制,就是依靠 ZAB 实现的。它实现了崩溃回复和消息广播两个主要功能。

ZAB协议保证数据一致性的两个重要特点就是:

1、ZAB协议需要确保那些已经在 leader 服务器上提交的事务最终被所有服务器都提交。

2、ZAB协议需要确保丢弃那些只在 leader 服务器上被提出的事务。

为了解决单点故障,有leader选举算法。在leader选举中,如果让 leader 选举算法能够保证新选举出来的 leader 服务器拥有集群中所有机器最高事务编号(ZXID)的事务proposal,那么就可以保证这个新选举出来的 leader 一定具有所有已经提交的提案。

因为事务的每次执行都会有一个编号,最高事务编号代表着最新的事务,即最新的数据。 根据上述ZAB协议内容,ZooKeeper实现了分布式系统数据的一致性!

4. 鸽巢原理

简单描述:若有n个笼子和n+1只鸽子,所有的鸽子都被关在鸽笼里,那么至少有一个笼子有至少2只鸽子 。

带你了解分布式系统的数据一致性问题-LMLPHP

5. Quorum NWR机制

Quorum NWR:Quorum 机制是分布式场景中常用的,用来保证数据安全,并且在分布式环境中实现最终一致性的投票算法。这种算法的主要原理来源于鸽巢原理。它最大的优势,既能实现强一致性,而且还能自定义一致性级别!

N:总节点数

W:总写入成功数

R:总读取数

当W+R>N时,一定能保证读到最新的数据,即强一致性! 为什么这样说?

带你了解分布式系统的数据一致性问题-LMLPHP

如上图,有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就是这么干的!采用了第三种情况!

6. CAP理论

根据上述说的,做到强一致性了,就难做到高可用,两者是非常矛盾的。所以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理论。

7. BASE理论

多数情况下,其实我们也并非一定要求强一致性,部分业务可以容忍一定程度的延迟一致,所以为了兼顾效率,发展出来了最终一致性理论 BASE,它的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

一句话就是做事别走极端,BASE 是对 CAP 理论中的 C 和 A 进行权衡得到的结果。

BASE理论做到的不是强一致,而是最终一致;不是高可用,而是基本可用。

Basically Available(基本可用):基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。 例如:淘宝双11,为保护系统稳定性,正常下单,其他边缘服务可暂时不可用。

Eventually Consistent(最终一致):最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。

以后开发分布式系统,就可以根据业务来决定到底追求高可用还是追求强一致性!

8. 总结

好啦,分布式系统的数据一致性问题大致聊得差不多了,老刘主要给大家讲了讲分布式系统一致性的背景以及实现。尽管当前水平可能不及各位大佬,但老刘还是希望能够变得更加优秀,能够帮助更多自学编程的伙伴。

如果有相关问题,请联系公众号:努力的老刘,和老刘进行愉快的交流,如果觉得帮到了您,不妨点赞关注支持一波!

带你了解分布式系统的数据一致性问题-LMLPHP

 

01-11 06:46