分布式系统协议Raft

Raft

leader-based的共识算法
raft会先选出leader,leader完全负责replicated log的管理。leader负责接受所有客户端更新请求,然后复制到follower节点,并在安全的时候执行这些请求。如果leader故障,follower会重新选出新的leader

是一种实现分布式一致性的协议。

节点状态

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

Leader Election

Leader选举
所有节点启动时都是follower状态;
在一段时间内如果没收到来自leader的心跳,从follower切换到candidate,发起选举;
如果收到majority的选票(含自己的一票)则切换到leader状态;
如果发现其他节点比自己更新,则主动切换到follower
系统中最多只有一个leader,如果在一段时间里没发现leader,则大家通过投票选出leader。leader会不停的给follower发心跳消息,表明自己的存活状态。如果leader故障,那么follower会转换成candidate,重新选出leader。
如果出现平票的情况,那么就延长系统不可用的时间(没有leader就无法处理客户端写请求),因此raft引入了randomized election timeouts来尽量避免平票情况


leader选举
  1. 节点一开始是follower状态


    初始化
  2. 如果followers没有收到来自leader的信息,变成candidate


    follower->candidate
  3. candidate向其他节点请求投票


    请求投票
  4. 节点响应投票


    响应投票
  5. candidate如果获取到大多数节点的投票,就成为leader


    成为leader

Log Replication

日志复制
客户端的一切请求发送到leader,leader来调度这些并发请求的顺序,并且保证leader与follower状态的一致性。raft的做法是将这些请求以及执行顺序告知followers。leader和followers以相同的顺序来执行这些请求,保证状态一致。

  1. 对系统的所有更改现在将通过leader。
    每个改变作为一个entry加入到node的日志里。
    日志entry当前是未提交状态,所以不会更新节点的值


    向leader发起更改
  2. 为了提交entry,节点首先将它复制到follower节点


    日志复制
  3. leader等待大多数节点写入entry。
    现在leader上已经提交了entry,节点状态是“5”


    多数节点写入了entry
  4. leader通知followers,entry已经提交。
    集群现在已经就系统状态达成一致


    通知followers提交entry

Leader选举详细过程

在Raft中,有两种timeout设置来控制选举
第一个是election timeout
follower成为candidate前所需等待的时间。选举超时随机设置为150ms~300ms

  1. 超过election timeout后,follower成为candidate,开启一个新的选举任期(term)。
    投票给自己,发送请求投票(Request Vote)消息给其他节点


    超时后成为候选者

    向其他节点发送请求投票
  2. 如果接收节点在此期间尚未投票,它会投票给这个candidate。
    接收节点重置它的election timeout


    投票给candidate
  3. 一旦一个candidate有多数的投票,它就成为leader


    candidate成为leader
  4. leader开始发送Append Entries消息给它的followers
    这些消息按heartbeat timetout的间隔来发送
    leader发送心跳消息
  5. 然后Followers响应每个Append Entries消息
    这一选举任期(term)会持续直到一个follower停止接收心跳并成为candidate


    followers响应消息

停掉leader,重新选举

  1. 节点C是任期(term)2的leader
    需要多数投票才能保证在每个任期里只有一个leader被选举出来
    如果有两个节点同时成为candidate,则可能会发生分离投票


    任期2,节点C是leader
  2. 两个节点在相同任期(term)里同时开始启动选举
    每个在另一个之前到达一个follower
    现在每个candidate有两票,且在本任期内不能接收到更多选票
    此时候选者会等待选举超时,然后发起新一轮选举


    两个节点同时启动选举

    每个分别先到达一个follower
  3. 这时候新的一轮,节点C接受了多数投票,成为leader


    新一轮投票选出leader

日志复制详细过程

一旦选出了一个leader,就需要将系统的所有更改复制到所有节点
这是通过使用与心跳相同的Append Entries消息来完成。

  1. 首先客户端发送一个变更到leader
    此变更被追加到leader的日志


    客户端发送变更
  2. 此变更在下一次心跳的时候发送到followers


    发送变更到followers

    follower追加日志
  3. 一旦多数followers响应,entry被提交。响应发送给客户端


    响应发给客户端
  4. 客户端发送增加2的变更,系统值被更新为“7”


    系统值变更

网络分区

raft也能在网络分区的情况下保持一致性

  1. 网络分区产生


    产生网络分区
  2. 现在有两个不同的leader在不同的任期(term)内


    两个任期,两个leader
  3. 增加一个客户端,一个客户端尝试将节点B的值设置为“3”
    节点B不能复制到多数节点,所以日志entry保持未提交状态


    节点B尝试设置为3
  4. 另一个客户端尝试设置节点C的值为“8”
    此时将成功,因为可以复制到多数节点


    节点C尝试设置为8
  5. 修复网络分区
    节点B将看到更高的选举任期并下台
    此时节点A和B将回滚未提交的entries,匹配新的leader的日志
    此时集群里的日志将保持一致


    修复网络分区,节点B下台

参考链接

http://thesecretlivesofdata.com/raft/

你可能感兴趣的:(分布式系统协议Raft)