vlambda博客
学习文章列表

分布式选举-Raft算法-1 Leader选举 原理

Raft理论是分布式数据一致性算法,为了便于理解Raft算法分成了4个部分:

  • Leader选举

  • 日志复制

  • 成员变更

  • 日志压缩


此系列文章先来分析Raft Leader选举的原理及实现,在后续《分布式数据复制》的系列文章中,我们再回过头来实现Raft算法的其他功能。


Leader选举:

选举原则:典型的投票选举算法(少数服从多数),也就是说,在一定周期内获得投票最多的节点成为主节点。


节点角色:

  • Leader,主节点,一个任值周期内只有一个主节点。

  • Candidate,候选节点,集群中没有Leader时发起投票,进行选举。

  • Follower,跟随节点,即主节点的从节点。


消息类型:

  • Vote,投票消息

  • Heartbeat,心跳消息,Follower接收Leader的心跳消息,重置选举计时器。


选举过程:

  1. 节点刚启动时,默认是Follower状态。

  2. 启动之后,开启选举超时定时器,节点切换到Candidate状态,发起选举请求。

  3. 当Candidate状态的节点,接收到超过半数的投票,则成为主节点,切换到Leader状态。每一轮选举,每个节点只能投一次票。

  4. Leader状态的节点向其他节点发送心跳消息,其他Candidate状态的节点切换回Follower状态,并重置选举超时定时器。

  5. Leader节点收到更高任期号的消息,切换到Follower状态。这种情况主要发生在有网络分区时。


假设有5个节点,选举过程如下图:

  1. 初始5个节点为Follower状态,任职周期为1(Term=1)。

  2. 节点切换为Candidate状态,开启选举定时器,任值周期加1(Term=2)。先为自己投票,然后向其他节点请求投票。

  3. 得票数超过节点半数的节点,切换为Leader状态,并向其他4个节点发送心跳消息。其他4个节点切换为Follower状态。


网络分区:

下面看看,当发生网络分区时,节点状态如何切换。如下图:

网络发生A、B两个分区,A分区的3个节点继续提供服务。B分区的2个节点由于没有收到Leader节点的心跳消息,在选举定时器超时后,切换到Candidate状态,开始进行投票选举,任职周期加1(Term=3)。


当网络恢复后,A分区节点的任值周期(Term=2)比B分区节点的任值周期(Term=3)小,因此A分区的节点切换成Follower状态,5个节点开始进行投票选举,最终选举出Leader节点。


问题:如何避免网络恢复后,不发生切主?

如上图,B分区的2个节点由于永远得不到超过半数的投票,所以任职周期不断累加。当网络恢复后,原来的Leader由于任职周期小,切换为Follower状态,集群重新选主。


如何避免重新选主,将投票阶段分拆成两阶段,即预投票阶段和投票阶段。

预投票阶段:任职周期不累加,选出得票数过半的节点。

投票阶段:由在预投票阶段选出的节点发起投票请求,任职周期累加,最终选出主节点。


这样,B分区2个节点的任值周期就会小于等于原Leader的任值周期,当网络恢复后就不会重新选主。


开源软件应用:Go语言编写的etcd组件,是一个高可用,强一致的数据存储仓库,就是实现了Raft算法的选主和数据一致性,Kubernetes的选主就是使用的etcd组件。


总结:

Raft的选举算法,节点有三个角色:Leader、Candidate、Follower。有两种通信消息:投票消息,心跳消息。由选举定时器开启任值周期,在任值周期内得票过半的节点成为主节点。


优点是算法复杂度低,易于实现,主节点稳定,不会轻易发生切主。缺点是集群内节点需要全通信,通信量比较大。


Raft算法的Leader选举原理讲解完了,下一篇文章《分布式选举-Raft算法-2 Leader选举 代码实现》我们来具体看看如何用代码实现分布式环境下的Raft Leader选举。





鼓励一下,点个“在看”