一、为什么需要 Gossip 协议?
为了实现 BASE 理论中的“最终一致性原则”。两阶段提交协议和 Raft 算法需要满足“大多数服务节点正常运行”原则,如果希望系统在少数服务节点正常运行的情况下,仍能对外提供稳定服务,这时就需要实现最终一致性。
在我看来,你可以通过 Gossip 协议实现这个目标。
Gossip 协议,顾名思义,就像流言蜚语一样,利用一种随机、带有传染性的方式,将信息传播到整个网络中,并在一定时间内,使得系统内的所有节点数据一致。对你来说,掌握这个协议不仅能很好地理解这种最常用的,实现最终一致性的算法,也能在后续工作中得心应手地实现数据的最终一致性。
二、如何实现最终一致性?
在介绍Gossip协议的具体实现前,我们先来看看实现最终一致性有哪些方法。
-
读时修复:在读取数据时,检测数据的不一致,进行修复。比如 Cassandra 的 Read Repair 实现,具体来说,在向 Cassandra 系统查询数据的时候,如果检测到不同节点的副本数据不一致,系统就自动修复数据。
-
写时修复:在写入数据,检测数据的不一致时,进行修复。比如 Cassandra 的 Hinted Handoff 实现。具体来说,Cassandra 集群的节点之间远程写数据的时候,如果写失败就将数据缓存下来,然后定时重传,修复数据的不一致性。
-
异步修复:这个是最常用的方式,通过定时对账检测副本数据的一致性,并修复。
三、Gossip 协议是如何实现最终一致性的?
Gossip 的三板斧分别是:直接邮寄(Direct Mail)、反熵(Anti-entropy)和谣言传播(Rumor mongering)。
3.1、直接邮寄(Direct Mail)
直接邮寄:就是直接发送更新数据,当数据发送失败时,将数据缓存下来,然后重传。从图中你可以看到,节点 A 直接将更新数据发送给了节点 B、D。
在这里我想补充一点,直接邮寄虽然实现起来比较容易,数据同步也很及时,但可能会因为缓存队列满了而丢数据。也就是说,只采用直接邮寄是无法实现最终一致性的。
那如何实现最终一致性呢?答案就是反熵。本质上,反熵是一种通过异步修复实现最终一致性的方法。
3.2、反熵(Anti-entropy)
反熵指的是集群中的节点,每隔段时间就随机选择某个其他节点,然后通过互相交换自己的所有数据来消除两者之间的差异,实现数据的最终一致性:
可以看到,节点 A 通过反熵的方式,修复了节点 D 中缺失的数据。那具体怎么实现的呢?
其实,在实现反熵的时候,主要有推、拉和推拉三种方式。
-
推方式,就是将自己的所有副本数据,推给对方,修复对方副本中的熵:
-
拉方式,就是拉取对方的所有副本数据,修复自己副本中的熵:
-
理解了推和拉之后,推拉这个方式就很好理解了,这个方式就是同时修复自己副本和对方副本中的熵:
有很多人,会觉得反熵是一个很奇怪的名词。其实,你可以这么来理解,反熵中的熵是指混乱程度,反熵就是指消除不同节点中数据的差异,提升节点间数据的相似度,降低熵值。
另外需要你注意的是,因为反熵需要节点两两交换和比对自己所有的数据,执行反熵时通讯成本会很高,所以我不建议你在实际场景中频繁执行反熵,并且可以通过引入校验和(Checksum)等机制,降低需要对比的数据量和通讯消息等。
可以借鉴通信原理中数据校验方法,如奇偶校验、CRC校验和格雷码校验等方式,但是这些方式只能检测出错误,但是无法纠错,可以通过重传的方式进行纠错。
虽然反熵很实用,但是执行反熵时,相关的节点都是已知的,而且节点数量不能太多,如果是一个动态变化或节点数比较多的分布式环境(比如在 DevOps 环境中检测节点故障,并动态维护集群节点状态),这时反熵就不适用了。那么当你面临这个情况要怎样实现最终一致性呢?答案就是谣言传播。
3.3、谣言传播(Rumor mongering)
谣言传播,广泛地散播谣言,它指的是当一个节点有了新数据后,这个节点变成活跃状态,并周期性地联系其他节点向其发送新数据,直到所有的节点都存储了该新数据:
从图中你可以看到,节点 A 向节点 B、D 发送新数据,节点 B 收到新数据后,变成活跃节点,然后节点 B 向节点 C、D 发送新数据。其实,谣言传播非常具有传染性,它适合动态变化的分布式系统。
四、总结
gossip协议是很多开源中间件和区块链实现的一种底层通信机制,掌握它的原理和细节能更好的理解中间件和区块链的一些行为和分布式特性。
在实际场景中,实现数据副本的最终一致性时,一般而言,直接邮寄的方式是一定要实现的,因为不需要做一致性对比,只是通过发送更新数据或缓存重传,来修复数据的不一致,性能损耗低。在存储组件中,节点都是已知的,一般采用反熵修复数据副本的一致性。当集群节点是变化的,或者集群节点数比较多时,这时要采用谣言传播的方式,同步更新数据,实现最终一致。
优势:
-
学习成本:实现简单
-
扩展性:允许节点的任意增加和减少,新增节点的状态 最终会与其他节点一致。
-
容错:任意节点的宕机和重启都不会影响 Gossip 消息的传播,具有天然的分布式系统容错特性。可以在一定程度上避免网络分割带来的问题。
-
去中心化:无需中心节点,所有节点都是对等的,任意节点无需知道整个网络状况,只要网络连通,任意节点可把消息散播到全网。
-
性能:指数级一致性收敛。消息会以“一传十的指数级速度”在网络中传播,因此系统状态的不一致可以在很快的时间内收敛到一致。消息传播速度达到了 logN。 Gossip协议的最大的好处是,即使集群节点的数量增加,每个节点的负载也不会增加很多,几乎是恒定的。如Consul管理的集群规模能横向扩展到数千个节点。
劣势:
-
消息延迟:节点随机向少数几个节点发送消息,消息最终是通过多个轮次的散播而到达全网;不可避免的造成消息延迟。
-
消息冗余:节点定期随机选择周围节点发送消息,而收到消息的节点也会重复该步骤;不可避免的引起同一节点消息多次接收,增加消息处理压力。
五、参考资料
-
京东云|数据同步gossip协议原理与应用场景介绍
-
聊聊分布式Gossip协议
-
分布式一致性协议——Gossip