Raft笔记

Raft

 
分布式系统可以容错,在一部分server挂掉的时候仍然正常工作,而难点在于如何处理挂掉的server保存的数据不一致问题

 

novel features

  • Log 只从 leader 流向 server
  • Leader selection 包含在心跳检测中,使用randomized timer
  • Membership changes 用一种新算法,使前后集群的主体在转换时是重叠的

 
 

replicated state machine

基于replicated log

 

每个Server的log都以相同的顺序存储着相同的command,因此每个server的输出是相同的

 
 

高理解度的设计

方法:

  1. 问题分解:leader election, log replication, safety, and membership changes 将这些问题分解开,成子问题
  2. 简化状态空间:减少状态数量,增加机制上的限制(砍掉意义不大的功能

 
 

分解一致性问题

将一致性问题分解为三个子问题

  • Leader election
  • Log replication
  • Safety

 
 

Raft basic

Server states:

  • leader
  • follower
  • candidate

 

leader处理所有的客户端请求

 
 

term

Raft 将时间分为若干个任意长度的 term

每个term的开头都是一次election

 

若election的结果是平票,则这个term结束,没有leader,稍后会有一个新的term

 
 

机制

term 在 Raft 中扮演了逻辑时钟的角色,这让server察觉到谁是过时的leader

 

每个server存储一个term number

  • 如果发现自己的term number比别人小,则更新

  • 如果leader或candidate发现自己的term过时了,他会立马变成follower

  • 如果server收到了过时的request,则拒绝掉

 
 

RPC

  • **RequestVote RPC **: election
  • AppendEntries RPC : heartbeat (no log) & replicate log entries

 

如果一段时间没有收到响应,会重试RPC

所有RPC的发起都是并行的

 
 

Leader election

利用heartbeat发起election

每个Server一开始都是follower

leader会向所有follower发heartbeat,若follower一段时间没收到heartbeat,称为election timeout,则认为没有可用leader,于是发起election

 

election过程

一个follower增加他的term,转换成candidate,给自己投票,给每个server发 RequestVote RPC

 

他保持candidate的状态直到三种情况:

  • 他获胜
  • 另一个candidate获胜
  • 一段时间过后仍无胜者

 

candidate获胜条件:他获得了多数票

一旦赢得election,他将给其他server发heartbeat,通知他们新leader的存在并阻止新election的发起

 

在投票过程中,candidate也可以收来自于自称leader的AppendEntries RPC,如果发送者的term >= candidate,则自己变为follower。否则拒绝此RPC

 

避免split vote

randomized election timeouts : election timeout 是随机选取的

 
 

Vote 策略

  • 不投 candidate term < 自己term的
  • 不投 log 没自己新的
  • 如果此 term 已经投过票了,则不投了(votedFor存投的candidateId)
  • 其他情况,投

 

Up-to-date: comparing the index and term of the last entries in the logs

 
 

Log replication

 

  1. Leader收到client命令
  2. 写自己的log,new entry
  3. 给follower发AppendEntries RPC,复制此entry到 log
  4. 确保一致性同步后,leader执行此entry (最终会被所有server的状态机执行),并返回response给client
  5. 如果某个follower崩溃或运行慢,leader会无限重试AppendEntries RPC

 
 

Log

 

Log 三要素

  1. Log index
  2. Term: 方块上面的数字
  3. Command

 

commited: 一个entry被大多数server复制到了log

累积确认: 一个entry是commited,那么之前所有entry都是commited

apply: 一旦follower确认一个entry是commited,他将在自己的状态机执行此entry

 
 

Log Matching Property

 

  • 两个处在不同 log 的 entry 拥有相同的index和term,那么他们就是相同的
  • 两个处在不同 log 的 entry 拥有相同的index和term,那么他之前的所有entry都是相同的

 

确保上述第二条生效的措施:

AppendEntries RPC 中包含了leader的 prevLogIndex & prevLogTerm,如果follower没找到此prevEntry,则返回失败,拒绝新entry。因此,只要follower返回成功,通过归纳法,则之前的entry都和leader是一致的

 
 

Leader Crash

Lead crash的时候,log会不一致。老leader可能还没有commit entry就crash了

 
 

处理不一致 consistency check

consistency check 是通过 AppendEntries RPC 执行的

策略: leader 让 follower 强制复制 leader 的 log,如果有冲突,follower的 log 会被覆盖

过程

  1. leader找到与follower一致的最近点
  2. 删除后面的所有follower log
  3. leader将后面的所有leader log 发给 follower

 

leader会维护每个follower的nextIndex,用于发AppendEntries RPC时给他们

当leader刚当上时,nextIndex = 自己最后一个entry index + 1

 

consistency check失败后,leader会递减自己的nextIndex,然后重试AppendEntries RPC直到成功,一旦成功,follower就复制了后面的log,达到一致。

可优化为:follower返回冲突index的数量,leader直接减去,达到一致的index,这样只用重试一次

 
 

Follower and candidate crashes

如果这两种crash发生了,那么发给他们的RequestVote & AppendEntries RPCs 会失败,Raft会无限重试RPC直到成功。

 

Raft RPC 是幂等的,如果新entry到了,而follower已经有此entry了,则会忽略这些entry

 
 

Timing and availability

 

\[broadcastTime ≪ electionTimeout ≪ MTBF \]

 

MTBF: 一个server平均发生两次故障的间隔时间

 
 

实现心得

  1. 计时器到时触发时,可新开一个线程执行逻辑,而不应暂停计时同步处理
posted @ 2022-07-27 19:34  Numerz  阅读(47)  评论(0编辑  收藏  举报