美文网首页
Raft 协议

Raft 协议

作者: zh_harry | 来源:发表于2020-10-08 11:23 被阅读0次

    Raft 协议

    Raft 感觉是最容易理解的一个了,也很有意思。先说它的逻辑:

    Raft 协议的每个副本都会处于三种状态之一:Leader、Follower、Candidate。

    Leader:所有请求的处理者,Leader 副本接受 client 的更新请求,本地处理后再同步至多个其他副本 Follower:请求的被动更新者,从 Leader 接受更新请求,然后写入本地日志文件 Candidate:如果 Follower 副本在一段时间内没有收到 Leader 副本的心跳,则判断 Leader 可能已经故障,此时启动选主过程,此时副本会变成 Candidate 状态,直到选主结束。

    可以看出,跟 Paxos 的基本理念一样,首先最基本的 Flollow(接受者),如果 Follower 接收不到 Leader 的心跳,就会全部转化为Candidate(提议者),然后提议者开始“贿选”,直到选出 Leader 之后,所有没选上的 Candidate 退回到 Follower 状态,统一接收 Leader 领导。

    就是说只要 Leader 不挂掉,只要选举一次就行了,后面大家默认信任选出来的 Leader。

    另外,每一个副本都会维护一个 term,类似于一个逻辑时钟,每发生一个动作就会递增,通过比较每个提议的 term,副本会默认使用最新的 term,防止发生冲突。如果一个 Leader 或者 Candidate 发现自己的 term 不是最新的了,就会自动降级到 Follower,而如果一个 Follower 接收到低于自己当前 term 的提议,就会直接抛弃。

    基本原则了解之后,我们完善一下细节。

    在强 Leader 的帮助下,Raft 将一致性问题分解为了三个子问题:

    Leader 选举:当已有的 Leader 故障时必须选出一个新的 Leader。

    日志复制:Leader 接受来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与 Leader 保持一致。

    安全 safety 措施:通过一些措施确保系统的安全性,如确保所有状态机按照相同顺序执行相同命令的措施。

    另外丢两个非常清晰的 Raft 全流程动画演示,看完之后很容易理解:

    http://thesecretlivesofdata.com/raft/

    https://raft.github.io/

    选举过程

    我们从最初始的状态来模拟,假设一个集群有三个副本,刚启动的时候,大家都是 Follower。然后每个 Follower 会有一个倒计时(election timeout),在倒计时结束之前,如果没有收到任何 Leader 的心跳,或者其他 Candidate 的投票请求,就会转化为 Candidate,开始选举。

    变成 Candidate 之后,会先投自己一票,同时开启一个倒计时,然后向所有其他节点发起投票请求。如果在倒计时完成之前,没有成为 Leader 或者接收到其他 Leader 的消息,就会发起新一轮选举。

    当一个副本处于 Candidate 状态时,如果收到来自 Leader 的心跳消息,就会立即变身为 Follower。如果发出去的投票请求得到了半数节点的成功回应,就会立即变身为 Leader,并周期性地向其它节点广播心跳消息,以尽可能长期维持自己的统治地位。

    关于选举的更多细节:

    election timeout 会是一个一定范围内的随机值,因为如果所有节点的倒计时时间都一样,大家就会同时变成 Candidate,然后同时互相投票选举,加大了达成共识的难度,所以倒计时会稍微错开,就很容易率先选出来一个 Leader。

    成功选举 Leader 之后,Leader 会向所有节点发送心跳,然后心跳会重置每个节点的 election timeout 倒计时时间。

    即便错开了倒计时,仍然有可能出现多个 Candidate 同时竞争,如果两个 Candidate 获得的票数不一致还好说,其中一个必然是多数,变成了 Leader。但是如果恰巧节点总数是偶数,就有可能出现票数一样僵持的情况。这时候就会重新选举。(这里我觉得每个 Candidate 发一个随机数过去,谁更大听谁的也行...,当然即便这样也有可能一样大)

    数据同步

    节点选出来了,下面就应该进行数据同步了。当一个数据修改的请求过来,会直接找到 Leader 节点,所有的增删改查都由 Leader 受理。然后同步给各个 Follower。

    每次数据同步操作同时也是一个心跳,会更新 Follower 的 election timeout。另外只有当多数节点返回同步成功之后,Leader 才会给客户端返回操作成功。

    分区容错

    然后是最麻烦的部分,如果出现了网络分区怎么办?比如原本五个节点的集群,被分成了双节点和三节点的两个集群。

    假设原本的 Leader 在双节点的集群里面,那么这个集群会照常运作。而新出现的三个节点的集群,由于没有收到心跳,会开始选举,然后选出新的 Leader。这时候,如果有客户端发起请求,有可能发送到两个不同的 Leader 上面,如果发送到原来的那个 Leader 上,即双节点的集群中,Leader 把操作同步给 Follower,会发现收不到足够多的 Follower 响应(因为这个 Follower 还以为自己的集群是五个节点),然后就没办法同步数据。而三节点的新集群,就可以顺利更新数据。

    如果这时候网络恢复了,各个节点又可以正常通信,三节点集群中的 Leader 和 双节点集群中的 Leader 会互相通信,然后会发现三节点的 Leader 由于一直正常运行,term 值会不断增大,所以大家会采信他的数据。于是双节点的两台机器会回滚,然后全部接受新 Leader 的数据同步。

    相关文章

      网友评论

          本文标题:Raft 协议

          本文链接:https://www.haomeiwen.com/subject/uawcpktx.html