Gossip算法由于Cassandra而名声大噪,Gossip看似简单,但要真正弄清楚其本质远没看起来那么容易。为了寻求Gossip的本质,下面的内容主要参考Gossip的原始论文:<<Efficient Reconciliation and Flow Control for Anti-Entropy Protocols>>。git
Gossip算法如其名,灵感来自办公室八卦,只要一我的八卦一下,在有限的时间内全部的人都会知道该八卦的信息,这种方式也与病毒传播相似,所以Gossip有众多的别名“闲话算法”、“疫情传播算法”、“病毒感染算法”、“谣言传播算法”。算法
但Gossip并非一个新东西,以前的泛洪查找、路由算法都归属于这个范畴,不一样的是Gossip给这类算法提供了明确的语义、具体实施方法及收敛性证实。网络
Gossip算法又被称为反熵(Anti-Entropy),熵是物理学上的一个概念,表明杂乱无章,而反熵就是在杂乱无章中寻求一致,这充分说明了Gossip的特色:在一个有界网络中,每一个节点都随机地与其余节点通讯,通过一番杂乱无章的通讯,最终全部节点的状态都会达成一致。每一个节点可能知道全部其余节点,也可能仅知道几个邻居节点,只要这些节能够经过网络连通,最终他们的状态都是一致的,固然这也是疫情传播的特色。数据结构
要注意到的一点是,即便有的节点因宕机而重启,有新节点加入,但通过一段时间后,这些节点的状态也会与其余节点达成一致,也就是说,Gossip自然具备分布式容错的优势。并发
Gossip是一个带冗余的容错算法,更进一步,Gossip是一个最终一致性算法。虽然没法保证在某个时刻全部节点状态一致,但能够保证在”最终“全部节点一致,”最终“是一个现实中存在,但理论上没法证实的时间点。负载均衡
由于Gossip不要求节点知道全部其余节点,所以又具备去中心化的特色,节点之间彻底对等,不须要任何的中心节点。实际上Gossip能够用于众多能接受“最终一致性”的领域:失败检测、路由同步、Pub/Sub、动态负载均衡。分布式
但Gossip的缺点也很明显,冗余通讯会对网路带宽、CUP资源形成很大的负载,而这些负载又受限于通讯频率,该频率又影响着算法收敛的速度,后面咱们会讲在各类场合下的优化方法。优化
根据原论文,两个节点(A、B)之间存在三种通讯方式:.net
若是把两个节点数据同步一次定义为一个周期,则在一个周期内,push需通讯1次,pull需2次,push/pull则需3次,从效果上来说,push/pull最好,理论上一个周期内可使两个节点彻底一致。直观上也感受,push/pull的收敛速度是最快的。server
假设每一个节点通讯周期都能选择(感染)一个新节点,则Gossip算法退化为一个二分查找过程,每一个周期构成一个平衡二叉树,收敛速度为O(n2 ),对应的时间开销则为O(logn )。这也是Gossip理论上最优的收敛速度。但在实际状况中最优收敛速度是很难达到的,假设某个节点在第i个周期被感染的几率为pi ,第i+1个周期被感染的几率为pi+1 ,则pull的方式:
而push为:
显然pull的收敛速度大于push,而每一个节点在每一个周期被感染的几率都是固定的p(0<p<1),所以Gossip算法是基于p的平方收敛,也成为几率收敛,这在众多的一致性算法中是很是独特的。
个Gossip的节点的工做方式又分两种:
Anti-Entropy模式有彻底的容错性,但有较大的网络、CPU负载;Rumor-Mongering模式有较小的网络、CPU负载,但必须为数据定义”最新“的边界,而且难以保证彻底容错,对失败重启且超过”最新“期限的节点,没法保证最终一致性,或须要引入额外的机制处理不一致性。咱们后续着重讨论Anti-Entropy模式的优化。
协调机制是讨论在每次2个节点通讯时,如何交换数据能达到最快的一致性,也即消除两个节点的不一致性。上面所讲的push、pull等是通讯方式,协调是在通讯方式下的数据交换机制。协调所面临的最大问题是,由于受限于网络负载,不可能每次都把一个节点上的数据发送给另一个节点,也即每一个Gossip的消息大小都有上限。在有限的空间上有效率地交换全部的消息是协调要解决的主要问题。
在讨论以前先声明几个概念:
为了保证一致性,规定数据的value及version只有宿主节点才能修改,其余节点只能间接经过Gossip协议来请求数据对应的宿主节点修改。
精确协调但愿在每次通讯周期内都很是准确地消除双方的不一致性,具体表现为相互发送对方须要更新的数据,由于每一个节点都在并发与多个节点通讯,理论上精确协调很难作到。精确协调须要给每一个数据项独立地维护本身的version,在每次交互是把全部的(key,value,version)发送到目标进行比对,从而找出双方不一样之处从而更新。但由于Gossip消息存在大小限制,所以每次选择发送哪些数据就成了问题。固然能够随机选择一部分数据,也可肯定性的选择数据。对肯定性的选择而言,能够有最老优先(根据版本)和最新优先两种,最老优先会优先更新版本最新的数据,而最新更新正好相反,这样会形成老数据始终得不到机会更新,也即饥饿。
固然,开发这也可根据业务场景构造本身的选择算法,但始终都没法避免消息量过多的问题。
总体协调与精确协调不一样之处是,总体协调不是为每一个数据都维护单独的版本号,而是为每一个节点上的宿主数据维护统一的version。好比节点P会为(p1,p2,...)维护一个一致的全局version,至关于把全部的宿主数据看做一个总体,当与其余节点进行比较时,只需必须这些宿主数据的最高version,若是最高version相同说明这部分数据所有一致,不然再进行精确协调。
总体协调对数据的选择也有两种方法:
通过验证,Cassandra实现了基于总体协调的push/push模式,有几个组件:
三条消息分别对应push/pull的三个阶段:
还有三种状态:
Cassandra主要是使用Gossip完成三方面的功能:
Gossip是一种去中心化、容错而又最终一致性的绝妙算法,其收敛性不但获得证实还具备指数级的收敛速度。使用Gossip的系统能够很容易的把Server扩展到更多的节点,知足弹性扩展垂手可得。
惟一的缺点是收敛是最终一致性,不使用那些强一致性的场景,好比2pc。