分布式选举算法笔记
2019-10-19 本文已影响0人
周群力
定义问题

System Model

算法
1. Bully Algorithm
简单来说就是基于Membership list,id最大的当leader。选举过程会有各种发消息的逻辑,懒得去记,可以理解为本质上是基于All-to-All heartbeating timeout的failure detect(如图1)。
这么一想的话,zookeeper/etcd做选举(即基于membership List选最大id的节点当主节点)其实也是Bully Algorithm,只不过fail detect是通过centralized heartbeating(如图2,出自C3)做的,避免了脑裂问题。


缺点:
- 新节点加入/恢复时,会有频繁切主的问题
- 选举过程中如果不断有fail或者timeout,在异步模型中liveness没法保证。
3.个人理解,选举过程中如果不断有fail或者timeout,有节点不断fail、fail recover、fail,看起来连同步模型都没法保证liveness。
4.个人理解,通过All-to-All heartbeating做fail detect然后选主是有脑裂问题的。
注:看极客时间讲MongoDB是基于Bully的,觉得很不可思议,翻了下官网说是MongoDB也基于共识算法做选举。
2. Ring-based
节点在环上击鼓传花式的通信。没见过哪个系统用,遇到再复习吧
3. 基于共识算法
可以通过共识算法选主,如图3。能保证safety,但是(当不断有故障/高延迟timeout发生)依然不能保证liveness。

具体在实现时有很多可以优化的细节:
-
chubby的方案用到Master lease,避免新节点频繁切主。没细看是怎么实现的。
-
zookeeper是每个节点生成一个比zk file system里存的id更高的id,然后写入fs,id最高的成为主节点;为避免id冲突,加入了一个quorum 2pc。值得一提的是,为避免惊群效应,用的是Ring-based failure detect,如图4所示。
图4.zk中的fd
zk怎么解频繁切主问题?按这里的讲法,每个节点的数据id是用的本地存储的最大id,新加入节点没数据、数据id不会是最大,因此不会成为主节点、不会切主。 -
etcd用Raft选主的细节没看。
工程实践中
实践中我们做选举功能往往是基于zk/etcd这类中心化的线性化存储。此时System Model就变了,变成:
- N个processes和一个线性化存储
- 每个process有一个唯一id
- 假设线性化存储不会fail(线性化存储自己通过fo实现高可用,对外透明);如果线性化存储fail,那么系统无法选举,即选举算法并不对线性化存储容错
在这种System model下,选举算法的实现和抢锁的实现一样,有:
- 基于原子cas+Watch。
本质上是一种centralized failure detect,有惊群问题 - Ring-based failure detect
每个节点存储不同的id,所有id就是一个membership list。id最大的作为主节点,每个节点Watch比自己大的节点。