8、架构-分布式的共识

8、架构-分布式的共识

码农世界 2024-06-06 前端 99 次浏览 0个评论

     概述

   在正式探讨分布式环境中面临的各种技术问题和解决方案前,我 们先把目光从工业界转到学术界,学习几种具有代表性的分布式共识 算法,为后续在分布式环境中操作共享数据准备好理论基础。下面笔 者从一个最浅显的场景开始,引出本章的主题:

如果你有一份很重要的数据,要确保它长期存储在电脑上不会丢 失,你会怎么做?

         这不是什么脑筋急转弯的古怪问题,答案就是去买几块硬盘,在 不同硬盘上多备份几个副本。假设一块硬盘每年损坏的概率是5%,把 文件复制到另一块备份盘上,两块硬盘同时损坏而丢失数据的概率就 只有0.25%,如果使用三块硬盘存储则丢失数据的概率是0.00125%,四 块是0.0000625%,换言之,四块硬盘就可以保证数据在一年内有超过 99.9999%的概率是安全可靠的。

        在软件系统里,要保障系统的可靠性,采用的办法与上面用几个 备份硬盘来保障的方法并没有什么区别。单个节点的系统宕机导致数 据无法访问的原因可能有很多,譬如程序出错、硬件损坏、网络分 区、电源故障,等等,一年中出现系统宕机的概率也许还要高于5%, 这决定了软件系统也必须有多台机器,并且它们拥有一致的数据副 本,才有可能对外提供可靠的服务。

        在软件系统里,要保障系统的可用性,面临的困难与硬盘备份面 临的困难又有着本质的区别。硬盘之间是孤立的,不需要互相通信, 备份数据是静态的,初始化后状态就不会发生改变,由人工进行的文 件复制操作,很容易就保障了数据在各个备份盘中的一致性。然而在 分布式系统中,我们必须考虑动态的数据如何在不可靠的网络通信条 件下,依然能在各个节点之间正确复制的问题。将我们要讨论的场景 做如下修改:

        如果你有一份会随时变动的数据,要确保它正确地存储于网络中 的几台不同机器之上,你会怎么做?

         相信最容易想到的答案一定是“数据同步”:每当数据发生变 化,把变化情况在各个节点间的复制视作一种事务性的操作,只有系 统里每一台机器都反馈成功、完成磁盘写入后,数据的变化才宣告成 功。使用2PC/3PC就可以实现这种同步操 作。一种真实的数据同步应用场景是数据库的主从全同步复制(Fully Synchronous Replication),譬如MySQL集群,它在进行全同步复制 时,会等待所有Slave节点的Binlog都完成写入后,才会提交Master节 点的事务。(这个场景中Binlog本身就是要同步的状态数据,不应将 它看作指令日志的集合。)然而这里有一个明显的缺陷,尽管可以确 保Master节点和Slave节点中的数据是绝对一致的,但任何一个Slave 节点因为任何原因未响应均会阻塞整个事务,每增加一个Slave节点, 都会造成整个系统可用性风险增加一分。

        以同步为代表的数据复制方法,被称为状态转移(State Transfer),是较符合人类思维的可靠性保障手段,但通常要以牺牲 可用性为代价。我们在建设分布式系统的时候,往往不能承受这样的 代价,一些关键系统,在必须保障数据正确可靠的前提下,也对可用 性有非常高的要求,譬如系统要保证数据达到99.999999%可靠,同时 系统自身也要达到99.999%可用的程度。这就引出了我们的第三个问 题:

        如果你有一份会随时变动的数据,要确保它正确地存储于网络中 的几台不同机器之上,并且要尽可能保证数据是随时可用的,你会怎 么做?

         可靠性与可用性的矛盾造成了增加机器数量反而带来可用性的降 低。为缓解这个矛盾,在分布式系统里主流的数据复制方法是以操作 转移(Operation Transfer)为基础的。我们想要改变数据的状态, 除了直接将目标状态赋予它之外,还有另一种常用的方法是通过某种 操作,令源状态转换为目标状态。能够使用确定的操作促使状态间产 生确定的转移结果的计算模型,在计算机科学中被称为状态机(State Machine)。

        状态机有一个特性:任何初始状态一样的状态机,如果执行的命 令序列一样,则最终达到的状态也一样。如果将此特性应用在多参与 者的协商共识上,可以理解为系统中存在多个具有完全相同的状态机 (参与者),这些状态机能最终保持一致的关键就是起始状态完全一 致和执行命令序列完全一致。

        根据状态机的特性,要让多台机器的最终状态一致,只要确保它 们的初始状态是一致的,并且接收到的操作指令序列也是一致的即 可,无论这个操作指令是新增、修改、删除抑或是其他任何可能的程 序行为,都可以理解为要将一连串的操作日志正确地广播给各个分布 式节点。在广播指令与指令执行期间,允许系统内部状态存在不一致 的情况,即并不要求所有节点的每一条指令都是同时开始、同步完成 的,只要求在此期间的内部状态不能被外部观察到,且当操作指令序 列执行完毕时,所有节点的最终状态是一致的,则这种模型就被称为 状态机复制(State Machine Replication)

        考虑到分布式环境下网络分区现象是不可能消除的,甚至允许不 再追求系统内所有节点在任何情况下的数据状态都一致,而是采用 “少数服从多数”的原则,一旦系统中过半数的节点完成了状态的转 换,就认为数据的变化已经被正确地存储在了系统中,这样就可以容 忍少数(通常是不超过半数)的节点失联,减弱增加机器数量对系统 整体可用性的影响,这种思想在分布式中被称为“Quorum机制”。

        根据上述讨论,我们需要设计出一种算法,能够让分布式系统内 部暂时容忍不同的状态,但最终保证大多数节点的状态达成一致;同 时,能够让分布式系统在外部看来始终表现出整体一致的结果。这个 让系统各节点不受局部的网络分区、机器崩溃、执行性能或者其他因 素影响,都能最终表现出整体一致的过程,就被称为各个节点的协商 共识(Consensus)。

Paxos

        世界上只有一种共识协议,就是Paxos,其他所有共识算法都是 Paxos的退化版本。

                                                                                        ——Mike Burrows,Google Chubby作者

        Paxos是由Leslie Lamport(就是大名鼎鼎的LaTeX中的“La”) 提出的一种基于消息传递的协商共识算法,是当今分布式系统最重要 的理论基础,几乎就是“共识”二字的代名词。这个极高的评价出自 于提出Raft算法的论文,更显分量十足。虽然笔者认为Mike Burrows所言有些夸张,但是如果没有Paxos,那后续的Raft、ZAB等算 法,ZooKeeper、etcd等分布式协调框架、Hadoop、Consul等在此基础 上的各类分布式应用都很可能会延后好几年面世。

        为了解释清楚Paxos算法,Lamport虚构了一个名为“Paxos”的希 腊城邦,这个城邦按照民主制度制定法律,却没有一个中心化的专职 立法机构,而是靠着“兼职议会”(Part-Time Parliament)来完成 立法,无法保证所有城邦居民都能够及时了解新的法律提案,也无法 保证居民会及时为提案投票。Paxos算法的目标就是让城邦能够在每一 位居民都不承诺一定会及时参与的情况下,依然可以按照少数服从多 数的原则,最终达成一致意见。但是Paxos算法并不考虑拜占庭将军问 题,即假设信息可能丢失也可能延迟,但不会被错误传递。 Lamport在1990年首次发表了Paxos算法,选的论文题目就是“The Part-Time Parliament”。由于算法本身极为复杂,用希腊城邦作为 比喻反而使得描述更晦涩,论文的三个审稿人一致要求他把希腊城邦 的故事删掉。这令Lamport感觉颇为不爽,干脆就撤稿不发了,所以 Paxos刚刚被提出的时候并没有引起什么反响。八年之后(1998年), Lamport将此文章重新整理后投到ACM Transactions on Computer Systems。这次论文成功发表,Lamport的名气也确实吸引了一些人去 研究,但并没有多少人能弄懂他在说什么。时间又过去了三年(2001 年),Lamport认为前两次的论文没有引起反响,是因为同行们无法理 解他以“希腊城邦”来讲故事的幽默感,所以这一次他以“Paxos Made Simple”为题,在SIGACT News杂志上发表文章,放弃了“希腊 城邦”的比喻,尽可能用(他认为)简单直接、(他认为)可读性较 强的方式去介绍Paxos算法。情况虽然比前两次要好上一些,但以 Paxos本应获得的重视程度来说,这次依然只能算是应者寥寥。

        这一段 听起来如同网络段子一般的经历被Lamport以自嘲的形式放到了他的个 人网站上。尽管我们作为后辈应该尊重Lamport老爷子,但当笔者 翻开“Paxos Made Simple”的论文,见到只有“The Paxos algorithm,when presented in plain English,is very simple.”这 一句话的“摘要”时,心里实在是不得不怀疑Lamport这样写论文是不 是在恶搞审稿人和读者,在嘲讽“你们这些愚蠢的人类”。 虽然Lamport本人连发三篇文章都没能让大多数同行理解Paxos, 但2006年,在Google的Chubby、Megastore以及Spanner等分布式系统 都使用Paxos解决了分布式共识的问题,并将其整理成正式的论文发表 之后,得益于Google的行业影响力,辅以Chubby作者Mike Burrows那 略显夸张但足够吸引眼球的评价推波助澜,Paxos算法一夜间成为计算 机科学分布式这条分支中最炙手可热的概念,开始被学术界众人争相 研究。Lamport本人因其对分布式系统的杰出理论贡献获得了2013年的 图灵奖,随后才有了Paxos在区块链、分布式系统、云计算等多个领域 大放异彩的故事。

算法流程

下面,我们来正式学习Paxos算法(在本节中Paxos均特指最早的 Basic Paxos算法)。Paxos算法将分布式系统中的节点分为三类。

  1. 提案节点:称为Proposer,提出对某个值进行设置操作的节点, 设置值这个行为就被称为提案(Proposal),值一旦设置成功,就是不 会丢失也不可变的。注意,Paxos是典型的基于操作转移模型而非状态 转移模型来设计的算法,不要把这里的“设置值”类比成程序中变量 赋值操作,而应该类比成日志记录操作,在后面介绍的Raft算法中就直 接把“提案”叫作“日志”了。
  2. 决策节点:称为Acceptor,是应答提案的节点,决定该提案是否 可被投票、是否可被接受。提案一旦得到过半数决策节点的接受,即 称该提案被批准(Accept)。提案被批准即意味着该值不能被更改,也 不会丢失,且最终所有节点都会接受它。
  3. 记录节点:称为Learner,不参与提案,也不参与决策,只是单 纯地从提案、决策节点中学习已经达成共识的提案,譬如少数派节点 从网络分区中恢复时,将会进入这种状态。

        在使用Paxos算法的分布式系统里,所有的节点都是平等的,它们 都可以承担以上某一种或者多种的角色,不过为了便于确保有明确的 多数派,决策节点的数量应该被设定为奇数个,且在系统初始化时, 网络中每个节点都应该知道整个网络所有决策节点的数量、地址等信 息。

        在分布式环境下,如果我们说各个节点“就某个值(提案)达成 一致”,指的是“不存在某个时刻有一个值为A,另一个时刻又为B的 情景”。解决这个问题的复杂度主要来源于以下两个方面因素的共同 影响。

  • 系统内部各个节点通信是不可靠的,不论是对于系统中企图设 置数据的提案节点抑或是决定是否批准设置操作的决策节点,其发 出、收到的信息可能延迟送达、可能丢失,但不去考虑消息有传递错 误的情况。
  • 系统外部各个用户访问是可并发的,如果系统只会有一个用 户,或者每次只对系统进行串行访问,那单纯地应用Quorum机制,少 数节点服从多数节点,就足以保证值被正确地读写。

            第一点是网络通信中客观存在的现象,也是所有共识算法都要重 点解决的问题。对于第二点,详细解释如下。现在我们讨论的是“分 布式环境下并发操作的共享数据”的问题,即使先不考虑是否在分布 式的环境下,只考虑并发操作,假设有一个变量i当前在系统中存储的 数值为2,同时有外部请求A、B分别对系统发送操作指令,“把i的值 加1”和“把i的值乘3”,如果不加任何并发控制,将可能得到 “(2+1)×3=9”与“2×3+1=7”这两种可能的结果。

            因此,对同一个 变量的并发修改必须先加锁后操作,不能让A、B的请求被交替处理, 这也可以说是程序设计的基本常识。而在分布式的环境下,由于要同 时考虑到分布式系统内可能在任何时刻出现的通信故障,如果一个节 点在取得锁之后、在释放锁之前发生崩溃失联,这将导致整个操作被 无限期的等待所阻塞,因此算法中的加锁就不完全等同于并发控制中 以互斥量来实现的加锁,还必须提供一个其他节点能抢占锁的机制, 以避免因通信问题而出现死锁。 为了解决这个问题,分布式环境中的锁必须是可抢占的。

            Paxos算 法包括两个阶段,第一阶段“准备”(Prepare)就相当于上面抢占锁 的过程。如果某个提案节点准备发起提案,必须先向所有的决策节点 广播一个许可申请(称为Prepare请求)。提案节点的Prepare请求中 会附带一个全局唯一且单调递增的数字n作为提案ID,决策节点收到 后,将会给予提案节点两个承诺与一个应答。

            两个承诺是指:

    • 承诺不会再接受提案ID小于或等于n的Prepare请求;
    • 承诺不会再接受提案ID小于n的Accept请求。

      一个应答是指:

              在不违背以前的承诺的前提下,回复已经批准过的提案中ID最 大的那个提案所设定的值和提案ID,如果该值从来没有被任何提案设 定过,则返回空值。如果违反此前做出的承诺,即收到的提案ID并不 是决策节点收到的最大的ID,那允许直接对此Prepare请求不予理会。

      当提案节点收到了多数派决策节点的应答(称为Promise应答) 后,就可以开始第二阶段的“批准”(Accept)过程,这时有如下两 种可能的结果:

      • 如果提案节点发现所有响应的决策节点此前都没有批准过该值 (即为空),那说明它是第一个设置值的节点,可以随意地决定要设 定的值,将自己选定的值与提案ID组成一个二元组“(id,value)”, 再次广播给全部决策节点(称为Accept请求);
      • 如果提案节点发现响应的决策节点中已经有至少一个节点的应 答中包含值了,那它就不能够随意取值,而是必须无条件地从应答中 找出提案ID最大的那个值并接收,组成一个二元组 “(id,maxAcceptValue)”,再次广播给全部决策节点(称为Accept请 求)。

                当每一个决策节点收到Accept请求时,都会在不违背以前的承诺 的前提下,接收并持久化当前提案ID和提案附带的值。如果违反此前 做出的承诺,即收到的提案ID并不是决策节点收到过的最大的ID,那 允许直接对此Accept请求不予理会。

                当提案节点收到了多数派决策节点的应答(称为Accepted应答) 后,协商结束,共识决议形成,然后将形成的决议发送给所有记录节 点进行学习。整个过程的时序图如图6-1所示。

                整个Paxos算法的工作流程至此结束,如果你此前并未专门学习过 分布式的知识,可能还不能对Paxos算法究竟是如何解决协商共识的形 成具体的概念。下面笔者以一个更具体例子来讲解Paxos。

        工作实例

                假设一个分布式系统有五个节点,分别命名为S1、S2、S3、S4、 S5,五个节点都同时扮演着提案节点和决策节点的角色。这个例子中 只讨论正常通信的场景,不涉及网络分区。此时,有两个并发的请求 希望将同一个值分别设定为X(由S1作为提案节点提出)和Y(由S5作为 提案节点提出),以P代表准备阶段,以A代表批准阶段,这时可能发 生以下几种情况。

                情况一:譬如,S1选定的提案ID是3.1(全局唯一ID加上节点编 号),先取得了多数派决策节点的Promise和Accepted应答,此时S5选定 提案ID 4.5,发起Prepare请求,收到的多数应答中至少会包含1个此前 应答过S1的决策节点,假设是S3,那么S3提供的Promise中必将包含S1已 设定好的值X,S5就必须无条件地用X代替Y作为自己提案的值,由此整 个系统对“取值为X”这个事实达成一致,如图6-2所示。

        • 情况三:另外一种可能的结果是S5提案时Promise应答中并未包 含批准过X的决策节点,譬如应答S5提案时,节点S1已经批准了X,节 点S2、S3未批准但返回了Promise应答,此时S5以更大的提案ID获得了 S3、S4、S5的Promise应答,由于这三个节点均未批准过任何值,所以S3 将不再接收来自S1的Accept请求,因为它的提案ID已经不是最大的了, 这三个节点将批准Y的取值,整个系统最终会对“取值为Y”达成一 致,如图所示。
          • 情况四:从情况三可以推导出另一种极端的情况,如果两个提 案节点交替使用更大的提案ID,使得准备阶段成功、批准阶段失败, 那么这个过程理论上可以无限持续下去,形成活锁(Live Lock),如 图6-5所示。在算法实现中会引入随机超时时间来避免活锁的产生

                    虽然Paxos是以复杂著称的算法,但以上介绍都是基于Basic Paxos、以正常流程(未出现网络分区等异常)、通俗方式讲解的 Paxos算法,并未涉及严谨的逻辑和数学原理,也未讨论Paxos的推导 证明过程,理解起来应该不算太困难。 Basic Paxos的价值在于开拓了分布式共识算法的发展思路,但由 于它有如下缺陷,一般不会直接用于实践:Basic Paxos只能对单个值 形成决议,并且决议的形成至少需要两次网络请求和应答(准备和批 准阶段各一次),高并发情况下将产生较大的网络开销,极端情况下 甚至可能形成活锁。总之,Basic Paxos是一种很学术化但对工业化并 不友好的算法,现在几乎只用来做理论研究,实际的应用都是基于 Multi Paxos和Fast Paxos算法,接下来我们将会了解Multi Paxos以 及一些与它的理论等价的算法(如Raft、ZAB等算法) 

            Multi Paxos

                    在上一节的最后,笔者举例介绍了Basic Paxos的活锁问题,即两 个提案节点争相提出自己的提案,抢占同一个值的修改权限,导致整 个系统在持续性地“反复横跳”,外部看起来就像被锁住了一样。此 外,笔者还讲述过一个观点,分布式共识的复杂性主要来源于网络的 不可靠与请求的可并发两大因素,活锁问题与许多Basic Paxos异常场 景中所遭遇的麻烦,都可以看作源于任何一个提案节点都能够完全平 等地、与其他节点并发地提出提案而带来的复杂问题。为此,Lamport 提出了一种Paxos的改进版本——Multi Paxos算法,希望能够找到一 种两全其美的办法,既不破坏Paxos中“众节点平等”的原则,又能在 提案节点中实现主次之分,限制每个节点都有不受控的提案权利。这 两个目标听起来似乎是矛盾的,但现实世界中的选举就很符合这种在 平等节点中挑选意见领袖的情景。

                    Multi Paxos对Basic Paxos的核心改进是增加了“选主”的过 程,提案节点会通过定时轮询(心跳),确定当前网络中的所有节点 里是否存在一个主提案节点,一旦没有发现主节点,节点就会在心跳 超时后使用Basic Paxos中定义的准备、批准的两轮网络交互过程,向 所有其他节点广播自己希望竞选主节点的请求,希望整个分布式系统 对“由我作为主节点”这件事情协商达成一致共识,如果得到了决策 节点中多数派的批准,便宣告竞选成功。

                    选主完成之后,除非主节点 失联之后发起重新竞选,否则从此往后,就只有主节点本身才能够提 出提案。此时,无论哪个提案节点接收到客户端的操作请求,都会将 请求转发给主节点来完成提案,而主节点提案时,就无须再次经过准 备过程,因为可以认为在经过选举时的那一次准备之后,后续的提案 都是对相同提案ID的一连串的批准过程。也可以通俗理解为选主过 后,就不会再有其他节点与它竞争,相当于处于无并发的环境当中的 有序操作,所以此时系统中要对某个值达成一致,只需要进行一次批 准的交互即可。

                    这时候的二元组(id,value)已经变成了三元组 (id,i,value),这是因为需要给主节点增加一个“任期编号”,这 个编号必须是严格单调递增的,以应付主节点陷入网络分区后重新恢 复,但另外一部分节点仍然有多数派,且已经完成了重新选主的情 况,此时必须以任期编号大的主节点为准。节点有了选主机制的支持 后,在整体来看,就可以进一步简化节点角色,不去区分提案、决策 和记录节点,而是统统以“节点”来代替,节点只有主(Leader)和 从(Follower)的区别 。

                    下面我们换一个角度来重新思考“分布式系统中如何对某个值达 成一致”这个问题,可以把该问题划分为三个子问题来考虑,可以证 明(具体证明就不列在这里了,感兴趣的读者可参考Raft的论文)当 以下三个问题同时被解决时,即等价于达成共识:

            • 如何选主(Leader Election);
            • 如何把数据复制到各个节点上(Entity Replication);
            • 如何保证过程是安全的(Safety)。

                      在正常情况下,客户端向主节点发起一个操作请求,譬如提出 “将某个值设置为X”,此时主节点将X写入自己的变更日志,但先不 提交,接着在下一次心跳包中把变更X的信息广播给所有的从节点,并 要求从节点回复“确认收到”的消息,从节点收到信息后,将操作写 入自己的变更日志,然后向主节点发送“确认签收”的消息,主节点 收到过半数的签收消息后,提交自己的变更、应答客户端并且给从节 点广播可以提交的消息,从节点收到提交消息后提交自己的变更,至 此,数据在节点间的复制宣告完成。 

                      在异常情况下,网络出现了分区,部分节点失联,但只要仍能正 常工作的节点的数量能够满足多数派(过半数)的要求,分布式系统 就可以正常工作,这时的数据复制过程如下。      

              • 假设有S1、S2、S3、S4、S5五个节点,S1是主节点,由于网络故 障,导致S1、S2和S3、S4、S5之间彼此无法通信,形成网络分区。
              • 一段时间后,S3、S4、S5三个节点中的某一个(譬如是S3)最先 达到心跳超时的阈值,获知当前分区中已经不存在主节点,则它向所 有节点发出自己要竞选的广播,并收到了S4、S5节点的批准响应,加上 自己一共三票,即得到了多数派的批准,竞选成功,此时系统中会同 时存在S1和S3两个主节点,但由于网络分区,它们不会知道对方的存 在。
              •   这种情况下,客户端发起操作请求。
                • 如果客户端连接到了S1、S2其中之一,都将由S1处理,但由于 操作只能获得最多两个节点的响应,不构成多数派的批准,所以任何 变更都无法成功提交。
                • 如果客户端连接到了S3、S4、S5其中之一,都将由S3处理,此 时操作可以获得最多三个节点的响应,构成多数派的批准,是有效 的,变更可以被提交,即系统可以继续提供服务。
                • 事实上,以上两种情景很少能够并存。网络分区是由于软、 硬件或者网络故障而导致的,内部网络出现了分区,但两个分区仍然 能分别与外部网络的客户端正常通信的情况甚为少见。更多的场景是 算法能容忍网络里下线了一部分节点,按照这个例子来说,如果下线 了两个节点,系统仍能正常工作,如果下线了三个节点,那剩余的两 个节点就不可能继续提供服务了。
              • 假设现在故障恢复,分区解除,五个节点可以重新通信:
                • S1和S3都向所有节点发送心跳包,从各自的心跳中可以得知两 个主节点里S3的任期编号更大,它是最新的,此时五个节点均只承认S3 是唯一的主节点。
                • S1、S2回滚它们所有未被提交的变更。
                • S1、S2从主节点发送的心跳包中获得它们失联期间发生的所有 变更,将变更提交并写入本地磁盘。
                • 此时分布式系统各节点的状态达成最终一致。

                        下面我们来看第三个问题:“如何保证过程是安全的”。不知你 是否感觉到这个问题与前两个问题的差异呢?选主、数据复制都是很 具体的行为,但是“安全”就很模糊,什么算安全或者算不安全?

                        在分布式理论中,Safety和Liveness两种属性是有预定义的术 语,在专业的资料中一般翻译成“协定性”和“终止性”,这两个概 念也是由Lamport最先提出,当时给出的定义如下。

                • 协定性(Safety):所有的坏事都不会发生。
                • 终止性(Liveness):所有的好事都终将发生,但不知道是什么 时候。

                          这里我们不去纠结严谨的定义,仍通过举例来说明它们的具体含 义。譬如以选主问题为例,协定性保证了选主的结果一定有且只有唯 一的一个主节点,不可能同时出现两个主节点;而终止性则要保证选 主过程一定可以在某个时刻结束。由前面对活锁的介绍可知,在终止 性这个属性上选主问题是存在理论上的瑕疵的,可能会由于活锁而导 致一直无法选出明确的主节点,所以Raft论文中只写了对Safety的保 证,但由于工程实现上的处理,现实中几乎不可能会出现终止性的问 题。 以上这种把共识问题分解为“选主”、“复制”和“安全”三个 问题来思考、解决的思路,即“Raft算法”(在Raft的《一种可以让 人理解的共识算法》中提出),并获得了USENIX ATC 2014大会的Best Paper,后来更是成为etcd、LogCabin、Consul等重要分布式程序的实 现基础,ZooKeeper的ZAB算法与Raft的思路也非常类似,这些算法都 被认为是Multi Paxos的等价派生实现。

                  ChatGPT

                  Raft和ZAB(Zookeeper Atomic Broadcast)都是分布式一致性协议,它们在设计上有些不同,但目标都是在分布式系统中实现一致性。以下是对Raft和ZAB的详细介绍。

                  Raft

                  Raft协议由Diego Ongaro和John Ousterhout于2013年提出。它旨在提供一种更容易理解的一致性算法,同时保证与Paxos相同的强一致性。Raft将一致性问题分解为几个独立的子问题,使得它更容易实现和理解。

                  角色

                  1. Leader:处理所有客户端的请求并管理日志复制。
                  2. Follower:被动地接受来自Leader的指令。
                  3. Candidate:在选举过程中试图成为Leader的节点。

                  工作原理

                  1. Leader选举:

                    • 初始状态下所有节点都是Follower。
                    • 当Follower在一段时间内未收到Leader的心跳信息(Heartbeat)时,它会转换为Candidate,并发起Leader选举。
                    • Candidate向其他节点发送请求投票(RequestVote)消息,其他节点会对该请求进行响应。如果Candidate收到多数节点的选票,它就成为新的Leader。
                    • 新的Leader会开始发送心跳信息来维护其Leader地位。
                  2. 日志复制:

                    • Leader接收客户端的请求,将其作为日志条目添加到本地日志中。
                    • Leader将日志条目发送给所有Follower,要求它们进行复制。
                    • 当日志条目在大多数节点上被复制时,Leader将该日志条目应用到状态机并向客户端确认请求已完成。
                  3. 安全性保证:

                    • Raft保证日志的一致性,通过Leader选举和日志复制机制,确保所有节点最终应用相同的日志条目序列。

                  ZAB (Zookeeper Atomic Broadcast)

                  ZAB协议是Zookeeper中使用的一致性协议,专为Zookeeper的需求设计。ZAB的设计目标是提供高可用性和严格的一致性,特别适用于主从架构。

                  角色

                  1. Leader:管理写请求,生成事务ID,并进行事务的原子广播。
                  2. Follower:处理读请求并从Leader接收事务。
                  3. Observer:类似于Follower,但不参与Leader选举,不影响集群的写性能,主要用于扩展读性能。

                  工作原理

                  1. Leader选举:

                    • 当Zookeeper集群启动时,所有节点都会进行Leader选举。
                    • 通过投票机制,节点会选择一个拥有最高事务ID的节点作为Leader。
                    • 选举过程中,节点会不断交换彼此的投票信息,最终选举出Leader。
                  2. 同步阶段:

                    • 新的Leader当选后,会将其本地的最新事务同步给所有Follower。
                    • 同步完成后,Leader进入广播阶段,Follower也进入正常工作状态。
                  3. 广播阶段:

                    • Leader接收到写请求后,为每个请求分配一个唯一的事务ID。
                    • Leader将事务广播给所有Follower,并等待多数Follower的确认。
                    • 当多数Follower确认事务后,Leader将事务提交,并通知Follower进行提交。
                  4. 崩溃恢复:

                    • 如果Leader崩溃,Follower会检测到,并重新进行Leader选举。
                    • 新的Leader当选后,会进行同步阶段,确保所有节点的一致性。

                  比较Raft和ZAB

                  1. 应用场景:

                    • Raft:适用于一般的分布式系统,特别是需要易于理解和实现的场景。
                    • ZAB:专门为Zookeeper设计,适用于需要高可用性和严格一致性的分布式协调服务。
                  2. 选举机制:

                    • Raft:通过定时器和多数投票机制选举Leader。
                    • ZAB:通过投票机制选举拥有最高事务ID的节点作为Leader。
                  3. 日志复制:

                    • Raft:Leader负责日志条目的复制和提交。
                    • ZAB:Leader负责事务的广播和提交,Follower确认事务后提交。
                  4. 一致性保证:

                    • Raft:通过日志复制和多数节点确认保证一致性。
                    • ZAB:通过事务ID和多数节点确认保证一致性。

                  总结

                  Raft和ZAB都是实现分布式一致性的有效协议,但它们的设计目标和应用场景有所不同。Raft注重易于理解和实现,适用于广泛的分布式系统;而ZAB专为Zookeeper设计,注重高可用性和严格一致性,适用于分布式协调服务。

转载请注明来自码农世界,本文标题:《8、架构-分布式的共识》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,99人围观)参与讨论

还没有评论,来说两句吧...

Top