Raft-很容易理解的分布式一致性算法
单节点场景
你可以想象下我们的一个节点作为一个保存单一值的数据库服务,我们有一个client可以向server发送一个值。client与server的关系如下图:
如果client向server发送一个值为8,那么它们的关系将变成下图:
可以看到只有一个节点的时候就很容易达到协议共识。
多节点
有了上面的示例,我们不禁要问,当我们拥有多个节点时怎么来达成节点间的共识呢?
客户端的值8该怎么在节点a、b、c之间达成一致呢,这就是分布式共识的问题。
Raft
Raft就是分布式共识协议的一种实现。我们来看一看它是如何工作的。
首先,节点有三种状态:
- Follower(跟随节点)
- Candidate(候选节点)
- Leader(领导节点)
下文中的Term代表的是任期
所有的节点在最开始的时候都是follower状态:
如果followers没有接收到leader的心跳请求(这里有一个超时时间,超过这个时间就认为没有接收到)然后它们就会变成candidate节点,如下图中的a节点:
然后candidate节点(图中a节点)开始请求其他节点投票。节点b和c将会回复给出他们的投票。
如果这时候candidate节点得到了大多数节点的投票,它就会成为leader节点。这个过程就被称为选主。所有的系统变化都需要经过leader节点。
每个更改都作为一个条目添加到节点的日志中。此日志项当前未提交,因此不会更新节点的值。
要提交条目,节点首先需要将其复制到Follower节点中。
然后领导者等待,直到大多数节点都写了该条目。
现在,该条目已提交到Leader节点上,并且节点状态为“ 5”。
然后Leader通知Follower该条目已提交。
现在,集群已就系统状态达成共识。此过程称为日志复制。
选举
在Raft中,有两个超时设置可控制选举。
首先是选举超时。选举超时是指追随者成为候选人之前所等待的时间。选举超时被随机分配在150毫秒至300毫秒之间。选举超时后,关注者成为候选人并开始新的选举任期:
图中Node C超时后为自己投票,并向其他节点发送请求投票消息。
如果接收节点在这个选举周期内还没有投票,那么它将投票给候选人:
在投票的同时会对节点重置其选举超时。
一旦候选人获得多数票,便成为Leader:
Leader开始向其Follower发送“ 添加条目”消息。
这些消息以心跳超时指定的时间间隔发送。Follower然后响应每个追加条目消息。
此选举任期将持续到Follower停止接收心跳并成为候选人为止:
让我们停止Leader,观察选举连任:
假设图中节点B先达到选举超时率先变成Candidate节点,它将成为任期2的负责人:
节点B向节点A和节点C请求投票,但是只有节点A返回了投票响应:
成为Leader的另一个条件是要获得多数票,这样可以确保每个任期只能选出一位Leader。如果两个节点同时成为候选节点,则可能会发生拆分表决。
让我们看一个分割投票的例子:
如果节点A和节点C都开始以相同的任期进行选举:
每个都先到达一个Follower节点:
现在,每位候选人都有2票,并且在这个任期中将无法获得更多选票:
这时Node节点将会等待一个新的超时时间重新进行投票:
节点C在第5届中获得了多数选票,因此成为领导者:
日志复制
当选出一位Leader后,我们需要将系统的所有更改复制到所有节点:
通过使用与心跳相同的“ 添加条目”消息来完成此操作。让我们逐步完成该过程。
首先,客户将更改发送给Leader:
更改将添加到Leader的日志中:
然后将更改在下一个心跳发送给Follower,一旦大多数Follower认可,便提交该条目:
然后将响应发送给客户端:
现在,让我们发送一条命令,将值增加“2”:
我们的系统值现在更新为“7”:
网络分区
Raft甚至可以在面对网络分区时保持一致:
对上图中一个集群,让我们添加一个分区以将A&B与C,D&E分开:
由于我们的分区,我们现在有两位Leader。让我们添加另一个客户端,并尝试更新两个领导者。
一个客户端将尝试将节点B的值设置为“ 3”
节点B无法复制为多数,因此其日志条目保持未提交状态。
另一个客户端将尝试将节点E的值设置为“ 8”
这将成功,因为它可以复制到大多数
现在让我们修复网络分区
节点B将看到较高的选举任期并退出Leader角色。节点A和B都将回滚其未提交的条目并匹配新领导者的日志。
现在,我们的日志在整个集群中是一致的。
参考
文章译自:http://thesecretlivesofdata.com/raft/
另外,网络上有一张比较经典的图片描述本文的:
图片来自:https://www.codedump.info/post/20180921-raft/