分布式的基石 - Paxos 算法和 Gossip 协议

1. Paxos 的诞生

Paxos 是由 Leslie Lamport 提出的 一种基于消息传递的协商共识算法,现已是当今分布式系统最重要的理论基础,几乎就是“共识”二字的代名词。这个极高的评价出自于提出 Raft 算法的论文,更是显得分量十足。如果没有 Paxos,那后续的 Raft、ZAB 等算法,ZooKeeper、Etcd 这些分布式协调框架、Hadoop、Consul 这些在此基础上的各类分布式应用都很可能会延后好几年面世。

为了解释清楚 Paxos 算法,Lamport 虚构了一个名为 “Paxos” 的希腊城邦,这个城邦按照民主制度制定法律,却又不存在一个中心化的专职立法机构,立法靠着“兼职议会”(Part-Time Parliament)来完成,无法保证所有城邦居民都能够及时地了解新的法律提案、也无法保证居民会及时为提案投票。Paxos 算法的目标就是让城邦能够在每一位居民都不承诺一定会及时参与的情况下,依然可以按照少数服从多数的原则,最终达成一致意见。但是 Paxos 算法并不考虑 拜占庭将军 问题,即假设信息可能丢失也可能延迟,但不会被错误传递。

2. Paxos 算法流程

我们正式来学习 Basic Paxos 算法,Paxos 算法将分布式系统中的节点分为三类:

  • 提案节点(Proposer):提出对某个值进行设置操作的节点,设置值这个行为就被称之为 提案(Proposal),值一旦设置成功,就是不会丢失也不可变的。请注意,Paxos 是典型的基于操作转移模型而非状态转移模型来设计的算法,这里的“设置值”不要类比成程序中变量赋值操作,应该类比成日志记录操作,在后面介绍的 Raft 算法中就直接把“提案”叫作“日志”了。

  • 决策节点(Acceptor):是应答提案的节点,决定该提案是否可被投票、是否可被接受。提案一旦得到过半数决策节点的接受,即称该提案被 批准(Accept),提案被批准即意味着该值不能再被更改,也不会丢失,且最终所有节点都会接受该它。

  • 记录节点(Learner):不参与提案,也不参与决策,只是单纯地从提案、决策节点中学习已经达成共识的提案,譬如少数派节点从网络分区中恢复时,将会进入这种状态。

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

2.1. 复杂度因素分析

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

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

第一点是网络通信中客观存在的现象,也是所有共识算法都要重点解决的问题。

第二点即使先不考虑是不是在分布式的环境下,只考虑并发操作,假设有一个变量 i 当前在系统中存储的数值为 2,同时有外部请求 A、B 分别对系统发送操作指令:“把 i 的值加 1”和“把 i 的值乘 3”,如果不加任何并发控制的话,将可能得到“(2+1)×3=9”与“2×3+1=7”两种可能的结果。因此,对同一个变量的并发修改必须先加锁后操作,不能让 A、B 的请求被交替处理,这些可以说是程序设计的基本常识了。

在分布式的环境下,由于还要同时考虑到分布式系统内可能在任何时刻出现的通信故障,如果一个节点在取得锁之后,在释放锁之前发生崩溃失联,这将导致整个操作被无限期的等待所阻塞,因此 算法中的加锁就不完全等同于并发控制中以互斥量来实现的加锁,还必须提供一个其他节点能抢占锁的机制,以避免因通信问题而出现死锁

2.2. 算法中的两个阶段

为了这个问题,分布式环境中的锁必须是可抢占的。

(1) “准备”(Prepare)阶段

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

两个承诺 是指:

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

一个应答 是指:

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

(2) “批准”(Accept)阶段

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

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

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

当提案节点收到了多数派决策节点的应答(称为 Accepted 应答)后,协商结束,共识决议形成,将形成的决议发送给所有记录节点进行学习

注意: 形成决议才是整个过程的完结,而不是 Accepted 应答后。

整个过程的时序图如图所示。

1655777731430.jpg

整个 Paxos 算法的工作流程至此结束,如果你此前并未专门学习过分布式的知识,相信阅读到这里,很有可能的感受是对操作过程中每一步都能看懂,但还是不能对 Paxos 算法究竟是如何解决协商共识的形成具体的概念。下面笔者就不局限于抽象的算法步骤,以一个更具体例子来讲解 Paxos。

3. Paxos 工作实例

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

情况一:

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

paxos1.145e2dd6.png

例举这个情况,相信大家肯定会对结果产生疑问

显然 S5 的提案 ID=4.5 是大于 S1 的提案 ID=3.1 的,为什么最终的结果值不是 Y?

我们回过头去再仔细读三遍 “准备”(Prepare)阶段的两个承诺和一个应答,“批准”(Accept)阶段的两种可能的结果,S3 的应答规则是最值得关注也是最能解决这个疑问的:

S1 和 S5 是提案节点,S3 是决策节点:

  1. 根据时间线,S1 向 S3 提交 Prepare(3.1) 的请求 ;S3 节点此时按照承诺规则 S3 向 S1 返回 Promise(3.1, null) 的应答,S1 收到 Promise(3.1, null) 后,提交 Accept(3.1, X) 的请求,S3 收到 Accept(3.1, X) 后,向 S5 返回 Accepted(3.1, X) 的响应。
  2. S5 向 S3 提交 Prepare(4.5) 的请求,注意此时 S3 的应答是在 Accept(3.1, X) 之后的,返回的并不是 Promise(4.5, null),而应该是 Promise(4.5, X); S5 收到 Promise(4.5, X) 后,无条件接受 X 代替原本的 Y 作为自己的提案值,提交 Accept(4.5, X) 的请求。

只关注 S1、S3、S5 的之间的交互,此场景的时间线顺序如下:

  1. S1 向 S3 提交Prepare(3.1)的请求
  2. S3 向 S1 返回Promise(3.1, null)的响应
  3. S1 收到Promise(3.1, null)后,提交Accept(3.1, X)的请求
  4. S3 收到Accept(3.1, X)后,向 S5 返回Accepted(3.1, X)的响应
  5. S5 向 S3 提交Prepare(4.5)的请求
  6. S3 收到后发现已有设置值 X,向 S5 返回Promise(4.5, X)的响应
  7. S5 收到Promise(4.5, X)后,无条件接受 X 代替原本的 Y 作为自己的提案值,提交Accept(4.5, X)的请求
  8. S3 收到Accept(4.5, X)后,向 S5 返回Accepted(4.5, X)的响应

说到这里,似乎结论已经说服了我,但是第七步仍然存在疑问

S3 提供的 Promise 中必将包含 S1 已设定好的值 X,S5 就必须无条件地用 X 代替 Y 作为自己提案的值?如果提案节点发现响应的决策节点中,已经有至少一个节点的应答中包含有值了,那它就不能够随意取值了,必须无条件地从应答中找出提案 ID 最大的那个值并接受? 有了这个前提,一个值设置完成后,不是无法改变了吗?

其实这个疑问是对整个决策的生命周期存在的误解。协商结束,提案节点形成决议才是真正的流程结束,前边所有的过程都是在一个生命周期单元之内完成的。生命周期内,值一旦设置成功,就是不会丢失也不可变的。请注意,Paxos 是典型的基于操作转移模型而非状态转移模型来设计的算法,这里的“设置值”不要类比成程序中变量赋值操作,应该类比成日志记录操作。

情况二:

事实上,对于情况一,X 被选定为最终值是必然结果,但从图中可以看出,X 被选定为最终值并不是必定需要多数派的共同批准,只取决于 S5提案时 Promise 应答中是否已包含了批准过 X 的决策节点,譬如下图所示,S5发起提案的 Prepare 请求时,X 并未获得多数派批准,但由于 S3已经批准的关系,最终共识的结果仍然是 X。

paxos2.59e89ab0.png

实际上 X 被选定只取决于 S5 提案时 Promise 应答中是否已包含了批准过 X 的决策节点,并不是必定需要多数派的共同批准。

情况三:

当然,另外一种可能的结果是 S5提案时 Promise 应答中并未包含批准过 X 的决策节点,譬如应答 S5提案时,节点 S1已经批准了 X,节点 S2、S3未批准但返回了 Promise 应答,此时 S5以更大的提案 ID 获得了 S3、S4、S5的 Promise,这三个节点均未批准过任何值,那么 S3将不会再接收来自 S1的 Accept 请求,因为它的提案 ID 已经不是最大的了,这三个节点将批准 Y 的取值,整个系统最终会对“取值为 Y”达成一致。

paxos3.c646204c.png

这里 S5 提案时 Promise 应答中并不包含批准过 X 的决策节点,所以最终 S3 将不会再接收来自 S1的 Accept 请求,因为 S1 的提案 ID 已经不是最大的了,S3 节点将批准 Y 的取值。

情况四:

从情况三可以推导出另一种极端的情况,如果两个提案节点交替使用更大的提案 ID 使得准备阶段成功,但是批准阶段失败的话,这个过程理论上可以无限持续下去,形成活锁(Live Lock),如图所示。在算法实现中会引入随机超时时间来避免活锁的产生。

paxos4.33b9f31e.png

假设有两个提案 ID: A 和 B 且定义 A < B, 每次应答 总是 Promise(B, null) 在 Promise(A, null) 之后,而 Accepted(A, X) 总在 Promise(B, null) 之后,继续引入提案 ID: C > B > A 重复以上步骤,会导致永远无法得到批准,形成活锁(Live Lock)。

虽然 Paxos 是以复杂著称的算法,但以上介绍都是基于 Basic Paxos、以正常流程(未出现网络分区等异常)、通俗方式讲解的 Paxos 算法,并未涉及严谨的逻辑和数学原理,也未讨论 Paxos 的推导证明过程,对于普通的不从事算法研究的技术人员来说,理解起来应该也不算太困难。

Basic Paxos 的价值在于开拓了分布式共识算法的发展思路,但它因有如下缺陷,一般不会直接用于实践:Basic Paxos 只能对单个值形成决议,并且决议的形成至少需要两次网络请求和应答(准备和批准阶段各一次),高并发情况下将产生较大的网络开销,极端情况下甚至可能形成活锁。实际的应用都是基于 Multi Paxos 和 Fast Paxos 算法的,接下来我们将会了解 Multi Paxos 与一些它的理论等价的算法(如 Raft、ZAB 等算法)。

4. Multi Paxos 算法

Basic Paxos 的活锁问题,两个提案节点互不相让地争相提出自己的提案,抢占同一个值的修改权限,导致整个系统在持续性地“反复横跳”,外部看起来就像被锁住了一样。

分布式共识的复杂性,主要来源于网络的不可靠与请求的可并发两大因素,活锁问题与许多 Basic Paxos 异常场景中所遭遇的麻烦,都可以看作是 源于任何一个提案节点都能够完全平等地、与其他节点并发地提出提案而带来的复杂问题

为此,Lamport 专门设计了一种 Paxos 的改进版本“Multi Paxos”算法,希望能够找到一种两全其美的办法,既不破坏 Paxos 中“众节点平等”的原则,又能在提案节点中实现主次之分,限制每个节点都有不受控的提案权利,这两个目标听起来似乎是矛盾的,但现实世界中的选举就很符合这种在平等节点中挑选意见领袖的情景。

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

选主完成之后,除非主节点失联之后发起重新竞选,否则从此往后,就只有主节点本身才能够提出提案。此时,无论哪个提案节点接收到客户端的操作请求,都会将请求转发给主节点来完成提案,而主节点提案的时候,也就无需再次经过准备过程,因为可以视作是经过选举时的那一次准备之后,后续的提案都是对相同提案 ID 的一连串的批准过程。

也可以通俗理解为选主过后,就不会再有其他节点与它竞争,相当于是处于无并发的环境当中进行的有序操作,所以此时系统中要对某个值达成一致,只需要进行一次批准的交互即可,如图所示。

1655795021854.jpg

可能有人注意到这时候的二元组(id, value)已经变成了三元组(id, i, value),这是因为需要给主节点增加一个“任期编号”,这个编号必须是严格单调递增的,以应付主节点陷入网络分区后重新恢复,但另外一部分节点仍然有多数派,且已经完成了重新选主的情况,此时 必须以任期编号大的主节点为准

当节点有了选主机制的支持,在整体来看,就可以进一步简化节点角色,不去区分提案、决策和记录节点了,统统以“节点”来代替,节点只有主(Leader)和从(Follower)的区别,此时协商共识的时序图如图所示。

1655795175531.jpg

在这个理解的基础上,我们换一个角度来重新思考“分布式系统中如何对某个值达成一致”这个问题,可以把该问题划分做三个子问题来考虑,可以证明当以下三个问题同时被解决时,即等价于达成共识:

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

4.1. 如何选主问题

选主问题尽管还涉及许多工程上的细节,譬如心跳、随机超时、并行竞选,等等,但要只论原理的话,如果你已经理解了 Paxos 算法的操作步骤,相信对选主并不会有什么疑惑,因为 这本质上仅仅是分布式系统对“谁来当主节点”这件事情的达成的共识而已,下面直接来解决数据(Paxos 中的提案、Raft 中的日志)在网络各节点间的复制问题。

4.2. 数据复制问题

(1)正常情况

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

(2)异常情况

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

  1. 假设有 S1、S2、S3、S4、S5五个节点,S1是主节点,由于网络故障,导致 S1、S2和 S3、S4、S5之间彼此无法通信,形成网络分区(脑裂)。
  2. 一段时间后,S3、S4、S5三个节点中的某一个(譬如是 S3)最先达到心跳超时的阈值,获知当前分区中已经不存在主节点了,它向所有节点发出自己要竞选的广播,并收到了 S4、S5节点的批准响应,加上自己一共三票,即得到了多数派的批准,竞选成功,此时系统中同时存在 S1和 S3两个主节点,但由于网络分区,它们不会知道对方的存在。
  • 这种情况下,客户端发起操作请求:

    • 如果客户端连接到了 S1、S2之一,都将由 S1处理,但由于操作只能获得最多两个节点的响应,不构成多数派的批准,所以任何变更都无法成功提交。
    • 如果客户端连接到了 S3、S4、S5之一,都将由 S3处理,此时操作可以获得最多三个节点的响应,构成多数派的批准,是有效的,变更可以被提交,即系统可以继续提供服务。
    • 事实上,以上两种“如果”情景很少机会能够并存。网络分区是由于软、硬件或者网络故障而导致的,内部网络出现了分区,但两个分区仍然能分别与外部网络的客户端正常通信的情况甚为少见。更多的场景是算法能容忍网络里下线了一部分节点,按照这个例子来说,如果下线了两个节点,系统正常工作,下线了三个节点,那剩余的两个节点也不可能继续提供服务了。
  • 假设现在故障恢复,分区解除,五个节点可以重新通信了:

    • S1和 S3都向所有节点发送心跳包,从各自的心跳中可以得知两个主节点里 S3的任期编号更大,它是最新的,此时五个节点均只承认 S3是唯一的主节点。
    • S1、S2回滚它们所有未被提交的变更。
    • S1、S2从主节点发送的心跳包中获得它们失联期间发生的所有变更,将变更提交写入本地磁盘。
    • 此时分布式系统各节点的状态达成最终一致。

4.3. 如何保证过程安全

“如何保证过程是安全的”,不知你是否感觉到这个问题与前两个存在一点差异?选主、数据复制都是很具体的行为,但是“安全”就很模糊,什么算是安全或者不安全?

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

  • 协定性(Safety):所有的坏事都不会发生(something "bad" will never happen)。
  • 终止性(Liveness):所有的好事都终将发生,但不知道是啥时候(something "good" will must happen, but we don't know when)。

我们不去纠结严谨的定义,仍通过举例来说明它们的具体含义。譬如以选主问题为例,Safety 保证了选主的结果一定是有且只有唯一的一个主节点,不可能同时出现两个主节点;而 Liveness 则要保证选主过程是一定可以在某个时刻能够结束的。由前面对活锁的介绍可以得知,在 Liveness 这个属性上选主问题是存在理论上的瑕疵的,可能会由于活锁而导致一直无法选出明确的主节点,所以 Raft 论文中只写了对 Safety 的保证,但由于工程实现上的处理,现实中是几乎不可能会出现终止性的问题。

5. Gossip 协议

Paxos、Raft、ZAB 等分布式算法经常会被称作是“强一致性”的分布式共识协议,它的意思其实是在说“尽管系统内部节点可以存在不一致的状态,但从系统外部看来,不一致的情况并不会被观察到,所以整体上看系统是强一致性的”。与它们相对的,还有另一类被冠以 “最终一致性”的分布式共识协议,这表明系统中不一致的状态有可能会在一定时间内被外部直接观察到。许多重要分布式框架中都有应用的另一种具有代表性的“最终一致性”的分布式共识协议:Gossip 协议。

Gossip 最早由 施乐公司(Xerox) Palo Alto 研究中心在论文《Epidemic Algorithms for Replicated Database Maintenance》中提出的一种用于分布式数据库在多节点间复制同步数据的算法。从论文题目中可以看出,最初它是被称作“流行病算法”(Epidemic Algorithm)的,只是不太雅观,今天 Gossip 这个名字已经用得更为普遍了,除此以外,它还有“流言算法”、“八卦算法”、“瘟疫算法”等别名,这些名字都是很形象化的描述,反应了 Gossip 的特点:要同步的信息如同流言一般传播、病毒一般扩散。

Gossip 协议所解决的问题并不是直接与 Paxos、Raft 这些共识算法等价的,只是基于 Gossip 之上可以通过某些方法去实现与 Paxos、Raft 相类似的目标而已。一个最典型的例子是比特币网络中使用到了 Gossip 协议,用它来在各个分布式节点中互相同步区块头和区块体的信息,这是整个网络能够正常交换信息的基础,但并不能称作共识;比特币使用[工作量证明](Proof of Work,PoW)来对“这个区块由谁来记账”这一件事情在全网达成共识,这个目标才可以认为与 Paxos、Raft 的目标是一致的。

Gossip 的具体工作过程

我们来了解 Gossip 的具体工作过程。相比 Paxos、Raft 等算法,Gossip 的过程十分简单,它可以看作是以下两个步骤的简单循环:

  1. 如果有某一项信息需要在整个网络中所有节点中传播,那从信息源开始,选择一个固定的传播周期(譬如 1 秒),随机选择它相连接的 k 个节点(称为 Fan-Out)来传播消息。
  2. 每一个节点收到消息后,如果这个消息是它之前没有收到过的,将在下一个周期内,选择除了发送消息给它的那个节点外的其他相邻 k 个节点发送相同的消息,直到最终网络中所有节点都收到了消息,尽管这个过程需要一定时间,但是理论上最终网络的所有节点都会拥有相同的消息。

gossip.0eb19e80.gif

上图是 Gossip 传播过程的示意图,根据示意图和 Gossip 的过程描述,我们很容易发现 Gossip 对网络节点的连通性和稳定性几乎没有任何要求,它一开始就将网络某些节点只能与一部分节点[部分连通](Partially Connected Network)而不是以[全连通网络](Fully Connected Network)作为前提;能够容忍网络上节点的随意地增加或者减少,随意地宕机或者重启,新增加或者重启的节点的状态最终会与其他节点同步达成一致。Gossip 把网络上所有节点都视为平等而普通的一员,没有任何中心化节点或者主节点的概念,这些特点使得 Gossip 具有极强的鲁棒性,而且非常适合在公众互联网中应用

同时我们也很容易找到 Gossip 的缺点,消息最终是通过多个轮次的散播而到达全网的,因此它必然会存在全网各节点状态不一致的情况,而且由于是随机选取发送消息的节点,所以尽管可以在整体上测算出统计学意义上的传播速率,但对于个体消息来说,无法准确地预计到需要多长时间才能达成全网一致。另外一个缺点是消息的冗余,同样是由于随机选取发送消息的节点,也就不可避免的存在消息重复发送给同一节点的情况,增加了网络的传输的压力,也给消息节点带来额外的处理负载。

反熵(Anti-Entropy)和传谣(Rumor-Mongering)

达到一致性耗费的时间与网络传播中消息冗余量这两个缺点存在一定对立,如果要改善其中一个,就会恶化另外一个,由此,Gossip 设计了两种可能的消息传播模式:反熵(Anti-Entropy)和传谣(Rumor-Mongering),这两个名字都挺文艺的。

熵(Entropy)是生活中少见但科学中很常用的概念,它代表着事物的混乱程度。反熵的意思就是反混乱,以提升网络各个节点之间的相似度为目标,所以在反熵模式下,会同步节点的全部数据,以消除各节点之间的差异,目标是整个网络各节点完全的一致。 但是,在节点本身就会发生变动的前提下,这个目标将使得整个网络中消息的数量非常庞大,给网络带来巨大的传输开销。而传谣模式是以传播消息为目标,仅仅发送新到达节点的数据,即只对外发送变更信息,这样消息数据量将显著缩减,网络开销也相对较小。

猜你喜欢

转载自juejin.im/post/7111607589506875406
今日推荐