Raft算法 | 青训营笔记

114 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记

服务器通过共识算法,对某条操作是否添加进日志达成共识,各节点都顺序执行这份日志就能保持在一个一致的状态。

基础

节点类型

  • Leader:发起心跳,创建日志,同步日志
  • Candidate:Leader选举算法时的临时角色
  • Follower:接收来自Leader的心跳、日志同步

Follower == backup?

任期

term是一个raft时间段,term开始时进行election,数个Candidate尝试竞争Leader。一个term内一定要有一个Leader。term同时类似版本号,Candidate或Leader发现自己的term过期时立刻退回Follower。过期的term会更新到收到值。过期的term消息会被抛弃。

日志

  • entry:每一个事件成为entry。只有leader可以创建,格式为<term,index,cmd>
  • log:由entry构成的数组。index是在自己log中的序列。entry总是先被添加到leader自己的日志中,然后发起共识请求,达成共识的提交。Follower只能从Leader获取新日志和当前的commited index,然后应用到自己的log

选举

raft使用心跳机制来触发Leader选举

Leader的心跳包会刷新Follower的选举超时时间

只要有一个Follower超时时间到就会发起选举

Candidate获得多数选票成为Leader:N2+1\frac{N}{2} + 1

这个N怎么算,N个candidate?怎么知道有N个?还是说N个总结点?如果掉了很多节点但没过半是不是选举有概率进行非常多次?

Raft使用随机化选举超时时间来避免激烈的选举竞争。节点每次选举过后,设置一个随机的超时时间,各个节点的超时时间不同,使得大多数情况下只有一个服务器会率先超时然后完成选举。

日志复制(传播更新)

Leader生成entry写入自己的log,然后广播该entry

Follower收到entry加入自己的log,并返回同意。那我不同意呢?

leader收到了多数同意,就记这个entry是commited

对于entry,raft保证如下性质:

  • 在两个日志中,如果两个entry拥有一样的term和index,那么有相同的cmd

    • 因为只有leader可以产生entry
  • 再两个日志中,如果两个entry拥有一样的term和index,那么前面的entry一定相同

    • 一致性检查

一致性检查如下:Leader给每个follower维护nextIndex,表示下一条给他的entry索引。新Leader开始时,会将所有nextIndex设置为自己的index+1。如果一个Follower收到的nextIndex和自己的index不一致会返回失败,随后Leader逐步递减nextIndex并重试,最终到达一个一致的地方,并移除所有不一致的部分,修改为Leader所给的entries。至此Follower和Leader的日志达成一致。

安全性

选举限制

Candidate会拒绝entry比自己旧的投票请求。先比较term,在比较index

节点崩溃

Leader崩溃时,超时选举,选举期间服务不可用

Follower或Candidate崩溃只需要通过AppendEntriesRPC同步

响应时间/选举超时时间/机器平均健康时间

  • broadcastTime << electionTimeout : 使得Leader能通过心跳来避免频繁发生选举
  • electionTimeout << MTBF: 使得系统稳定运行,选举不可用时间只占全部时间的很小一部分