最近工作中用到了Consul,在学习过程中,发现它是基于Raft来做分布式一致性的。正巧以前学习过Raft, 那么就正好借此机会复习一下吧!
Raft算法
有一个网站用动画的形式生动的描述了Raft算法: Raft算法动画演示 , 如果你跟着这个动画过一遍,相信你很容易能理解它。
以下是我基于这个动画以及一些别的文章(最后有列出),对Raft算法的一些整理, 如果你还不了解Raft,建议你先看看这个动画。
Raft算法中的关键词
Log
在Raft集群中,主要的工作单元就是log entry(你可以认为是对状态的修改, 比如set X = 3)。
分布式一致性问题可以被分解为log的复制。我们称一串log entry为一个log。如果集群中的所有成员都赞同log entries以及它们的顺序,那么我们认为这个log是一致的。
有限状态机
有限状态机是有限个状态以及状态之间的转移的集合。当新的log被应用(即修改集群状态),状态机会在状态间进行转移。同一个log序列必须产生同样的状态。
节点集
节点集是所有参与到log复制的成员的总集。
法定个数
法定个数是一个节点集的大多数成员的个数。对于一个n个节点的集群而言,法定个数需要值多少(n/2)+1个成员。
比如说,如果节点集有5个成员,法定个数至少是3。如果法定个数的节点处于不可用状态,那么整个集群都将处于不可用状态,任何新的log都不能被提交。
已提交的log
如果一个log entry被持久地保存到了法定个数的节点上,那么称这个log entry已经被提交了。当log entry被提交时,它可以被应用。
领导人
在任何时间,节点集都会选出一个节点来做领导人。领导人负责接收新的log entry,把它复制到follower上,管理它的提交和应用。
Raft集群中每个节点的角色
每个节点可能的角色
- Leader
- Follower
- Candidate
节点角色的变化
有三个节点A,B, C。
每个节点初始时,都是Follower。 Follower经过一段时间还没有收到来自Leader的信息(因为这时候还没有Leader), 这时候角色变成Candidate。
A, B变成了Candidate,C还处于Follower状态。
Candidate会通过向其他节点请求投票的方式发起选举, 得到大多数票的Candidate会变成Leader。
A,B都向其他两个节点发起投票请求, 假设C投给了A, 这样A就变成了Leader。
前面这个过程叫做领导人选举
。
节点的状态变化可以用下图概括:
数据的一致性
数据流向
Raft 协议强依赖 Leader 节点的可用性来确保集群数据的一致性。数据的流向只能从 Leader 节点向 Follower 节点转移。
当 Client 向集群 Leader 节点提交数据后,Leader 节点接收到的数据处于未提交状态(Uncommitted),接着 Leader 节点会并发向所有 Follower 节点复制数据并等待接收响应,确保至少集群中超过半数节点已接收到数据后再向 Client 确认数据已接收。一旦向 Client 发出数据接收 Ack 响应后,表明此时数据状态进入已提交(Committed),Leader 节点再向 Follower 节点发通知告知该数据状态已提交。
异常情况处理
假设集群有两个网络分区, A属于分区1, B,C属于分区2。原本两个分区之间是可以通信的,并且A是整个集群的Leader。
这时候分区间的通信被隔断了,于是B,C收不到 Leader A的心跳将发起选举产生新的 Leader,假设是B。
这时候有两个Leader,原先的 Leader A独自在一个区,向它提交数据不可能复制到多数节点所以永远提交不成功。而向新的 Leader B提交数据可以提交成功。
网络恢复后A发现集群中有更新任期(Term)的Leader B则自动降级为 Follower 并从新 Leader 处同步数据达成集群数据一致。