分布式选举
一般分布式集群中会有主副节点的角色区分,主节点的存在,就可以保证其他节点的有序运行,以及数据库集群中的写入数据在每个节点上的一致性,所以当主节点故障时,我们需要选举出一个新的主节点来接管全局。
分布式选举算法
长者为大:Bully算法
即在所有活着的节点中,选取 ID 最大的节点作为主节点。
算法需要的三个消息
Election 消息,用于发起选举;
Alive 消息,对 Election 消息的应答;
Victory 消息,竞选成功的主节点向其他节点发送的宣誓主权的消息。
选举过程
- 集群中每个节点判断自己的 ID 是否为当前活着的节点中 ID 最大的,如果是,则直接向他其节点发Victory 消息,宣誓自己的主权;
- 如果自己不是当前活着的节点中 ID 最大的,则向比自己 ID 大的所有节点发送Election 消息,并等待其他节点的回复;
- 若在给定的时间范围内,本节点没有收到其他节点回复的 Alive 消息,则认为自己成为主节点,并向其他节点发送 Victory 消息,宣誓自己成为主节点;若接收到来自比自己ID 大的节点的 Alive 消息,则等待其他节点发送 Victory 消息;
- 若本节点收到比自己 ID 小的节点发送的 Election 消息,则回复一个 Alive 消息,告知其他节点,我比你大,重新选举。
优点
选举速度快、算法复杂度低、简单易实现。
缺点
需要每个节点有全局的节点信息,因此额外信息存储较多;
任意一个比当前主节点 ID 大的新节点或节点故障后恢复加入集群的时候,都可能会触发重新选举,成为新的主节点,如果该节点频繁退出、加入集群,就会导致频繁切主。
民主投票: Raft算法
Raft 算法是典型的多数派投票选举算法,其选举机制与我们日常生活中的民主投票机制类似,核心思想是“少数服从多数”。
两个步骤: Leader选举和状态复制
Raft中的三种角色
Leader,即主节点,同一时刻只有一个 Leader,负责协调和管理其他节点;
Candidate,即候选者,每一个节点都可以成为 Candidate,节点在该角色下才可以被选为新的 Leader;
Follower,Leader 的跟随者,不可以发起选举。
流程
- 初始化时,所有节点均为 Follower 状态。
- 开始选主时,所有节点的状态由 Follower 转化为 Candidate,并向其他节点发送选举请求。
- 其他节点根据接收到的选举请求的先后顺序,回复是否同意成为主。这里需要注意的是,在每一轮选举中,一个节点只能投出一张票。
- 若发起选举请求的节点获得超过一半的投票,则成为主节点,其状态转化为 Leader,其他节点的状态则由 Candidate 降为 Follower。Leader 节点与 Follower 节点之间会定期发送心跳包,以检测主节点是否活着。
- 当 Leader 节点的任期到了,即发现其他服务器开始下一轮选主周期时,Leader 节点的状态由 Leader 降级为 Follower,进入新一轮选主。
每一轮选举,每个节点只能投一次票。这种选举就类似人大代表选举,正常情况下每个人大代表都有一定的任期,任期到后会触发重新选举,且投票者只能将自己手里唯一的票投给其中一个候选者。
应用
Kubernetes 的选主采用的是开源的 etcd 组件。而,etcd 的集群管理器 etcds,是一个高可用、强一致性的服务发现存储仓库,就是采用了 Raft 算法来实现选主和一致性的。
vs Bully
稳定性更强
当有新节点加入或节点故障故障后恢复恢复后,会触发选主,但不一定会真正切主,除非新节点或的节点获得投票数过半,才会导致切主。
具有优先级的民主投票:ZAB 算法
ZAB 算法增加了通过节点 ID 和数据 ID 作为参考进行选主,节点 ID 和数据 ID 越大,表示数据越新,优先成为主。相比较于 Raft 算法,ZAB 算法尽可能保证数据的最新性。所以,ZAB 算法可以说是对 Raft 算法的改进。
- 对于Leader的任期,raft叫做term,而ZAB叫做epoch
- 在状态复制的过程中,raft的心跳从Leader向Follower发送,而ZAB则相反。
三种角色与四种状态
Leader,主节点;
Follower,跟随者节点;
Observer,观察者,无投票权。
Looking 状态,即选举状态。当节点处于该状态时,它会认为当前集群中没有 Leader,因此自己进入选举状态。
Leading 状态,即领导者状态,表示已经选出主,且当前节点为 Leader。
Following 状态,即跟随者状态,集群中已经选出主后,其他非主节点状态更新为Following,表示对 Leader 的追随。
Observing 状态,即观察者状态,表示当前节点为 Observer,持观望态度,没有投票权和选举权。
每个节点都有一个唯一的三元组 (server_id, server_zxID, epoch),server_id 表示本节点的唯一 ID;server_zxID 表示本节点存放的数据 ID,数据 ID 越大表示数据越新,选举权重越大;epoch 表示当前选取轮数,一般用逻辑时钟表示。 ZAB 算法选主的原则是:server_zxID 最大者成为 Leader;若 server_zxID 相同,则 server_id 最大者成为 Leader。
vs Raft
ZAB 算法性能高,对系统无特殊要求,采用广播方式发送信息,若节点中有 n个节点,每个节点同时广播,则集群中信息量为 n*(n-1) 个消息,容易出现广播风暴;
且除了投票,还增加了对比节点 ID 和数据 ID,这就意味着还需要知道所有节点的 ID 和数据ID,所以选举时间相对较长。但该算法选举稳定性比较好,当有新节点加入或节点故障恢复后,会触发选主,但不一定会真正切主,除非新节点或故障后恢复的节点数据 ID 和节点ID 最大,且获得投票数过半,才会导致切主。
弱一致性Gossip算法
Gossip算法每个节点都是对等的,即没有角色之分。Gossip算法中的每个节点都会将数据改动告诉其他节点(类似传八卦)。有话说得好:"最多通过六个人你就能认识全世界任何一个陌生人",因此数据改动的消息很快就会传遍整个集群。
*
步骤:
1.集群启动,如下图所示(这里设置集群有20个节点)
-
某节点收到数据改动,并将改动传播给其他4个节点,传播路径表示为较粗的4条线
-
收到数据改动的节点重复上面的过程直到所有的节点都被感染