一致性算法之:raft

分布式中数据一致性算法之raft

Posted by odin on March 16, 2020

包含raft角色转换原理和日志复制原理。

raft角色

  • leader:client请求统一入口,由所有节点选举产生。每个网络分区唯一。
  • candidate:候选人角色,当leader丢失后,follower节点与leader的心跳连接超过当前节点的心跳连接时间(每个节点的超时时间为150ms~300ms的随机数),follower节点变为candidate节点,对自身投票并且向其他节点发送投票请求,进行重新选举。
  • follower:所有节点都以follower状态开始,如果收到leader消息超市,将变为candidate状态。若candidate状态节点选举失败,集群中产生了新的leader则candidate节点状态重新变为follower。

raft原理

在raft中,每个节点会处于以下的3中状态。

  • leader
  • candidate
  • follower 三种角色的关系转换如下:

日志复制

  • leader本身产生日志,不提交。
  • leader向所有follower发送日志。
  • follower节点收到leader发送的日志后本地存储不提交,并向leader返回日志复制确认信息。
  • leader节点收到follower返回的日志确认信息,当数量超过1/2时leader提交日志,并向所有follower发送日志提交消息。
  • follower收到leader发送的日志提交消息后将日志提交。
  • 最终达到整个系统处于一致的状态。

raft选举机制

官网raft演示动画地址

演示总结: 上图中candidate节点A向B,C节点发起投票请求,1,2中A节点收到的投票超过所有节点的1/2,满足大多数原则,成功成为leader。

选举过程:
当follower在选举超时时间(election timeout)内未收到leader的心跳消息(append entries),则变成candidate状态。为了避免选举冲突,这个超时时间是一个150~300ms之间的随机数。成为candidate的结点发起新的选举期(election term)去“拉选票”:

  1. 重置自己的计时器
  2. 投自己一票发送
  3. Request Vote消息
    • 如果接收结点在新term内没有投过票那它就会投给此candidate,并重置它自己的选举超时时间。candidate拉到大部分选票就会成为leader,并定时发送心跳——Append Entries消息,去重置各个follower的计时器。当前Term会继续直到某个follower接收不到心跳并成为candidate。
    • 如果不巧两个结点同时成为candidate都去“拉票”怎么办?这时会发生Splite Vote情况。两个结点可能都拉到了同样多的选票,难分胜负,选举失败,本term没有leader。之后又有计时器超时的follower会变成candidate,将term加一并开始新一轮的投票。

raft日志复制

当发生改变时,leader会复制日志给follower结点,这也是通过Append Entries心跳消息完成的。raft原理中已经列举了Log Replication的过程。

日志复制

  • leader本身产生日志,不提交。
  • leader向所有follower发送日志。
  • follower节点收到leader发送的日志后本地存储不提交,并向leader返回日志复制确认信息。
  • leader节点收到follower返回的日志确认信息,当数量超过1/2时leader提交日志,并向所有follower发送日志提交消息。
  • follower收到leader发送的日志提交消息后将日志提交。
  • 最终达到整个系统处于一致的状态。

raft从网络分区恢复,多leader数据合并

Raft能够正确地处理网络分区(“脑裂”)问题。 假设A~E五个结点,B是leader。如果发生“脑裂”,A、B成为一个子分区,C、D、E成为一个子分区。

  • 此时C、D、E会发生选举,选出C作为新term的leader。这样我们在两个子分区内就有了不同term的两个leader。
  • 这时如果有客户端写A时,因为B无法复制日志到大部分follower所以日志处于uncommitted未提交状态。
  • 而同时另一个客户端对C的写操作却能够正确完成,因为C是新的leader,它只知道D和E。
  • 当网络通信恢复,B能够发送心跳给C、D、E了,却发现“改朝换代”了,因为C的term值更大,所以B自动降格为follower。然后A和B都回滚未提交的日志,并从新leader那里复制最新的日志。

解决网络分区合并未提交的数据不丢失,需要人为手动备份日志。