一致性算法 - Raft协议流程详解


-     引文    -java

我们上文总体的介绍了下Raft协议,Raft协议分区容忍的一致性协议的核心思想:一致性的保证不必定非要全部节点都保持一致,只要大多数节点更新了,对于整个分布式系统来讲数据也是一致性的。Raft 协议将概念分解成:Leader election、Log replication、Safety。Raft 把一致性协议划分为 Leader 选举、MemberShip 变动、日志复制、Snapshot 等几个几乎彻底解耦的模块,实现了模块化设计。git

Raft 设计原则是经过减小状态数量将状态空间简化:github

  • 日志不容许出现空洞 , 而且 Raft限制了日志不一致的可能性
  • 使用随机化时钟简化了领导选举的算法

-     领袖选举    -web

Raft协议为了保证Leader的健壮性,使用了如下技术保证选举的简单化实现:算法

  • 超时驱动:Heartbeat/Election timeout
    安全

  • 随机的超时时间:下降选举碰撞致使选票被瓜分的几率服务器

Raft协议为了保证选举投票的有效性,规定了一系列的投票原则:
微信

  • 在任一任期内,单个节点最多只能投一票
  • 候选人知道的信息不能比本身的少优先:投票节点经过对比Term(任期)和CommitId来判断是否投“赞成”票。
  • first-come-first-served 先来先得 :收到多个RequestVote RPC拉票,对首先到达的进行投票

Raft 总体选举流程以下:
架构

  • Candidate发起投票时将自身当前任期加1(NewTerm),并向集群中全部节点发起投票请求(RequestVote RPC:请求中包含新的任期值);app

  • follower节点 根据投票原则进行 投票
  • Candidate获得大于半数节点的“赞成”后成为Leader,与其余节点创建心跳,并更新全部节点的当前任期为NewTerm;
  • 若是不够半数,则选举失败,启用随机选举超时策略
    • 全部 Condidate 随机sleep (即timeout)一段时间,而后开始新一轮的选举。
    • 第一个苏醒 Condidate 会向全部 Condidate 发出投票给个人申请
    • 尚未苏醒的 Condidate 就只能投票给已经苏醒的 Condidate 。


-     日志复制    -

Raft 协议定义的日志格式以下:

(TermId, LogIndex, LogValue)其中 (TermId, LogIndex) 能肯定惟一一条日志

Raft 协议 复制策略规定一系列的原则:

  • 连续性:日志不容许出现空洞
  • 有效性:
    • 一个log被复制到大多数节点,就是committed,保证不会回滚
    • leader必定包含最新的committed log,所以leader只会追加日志,不会删除覆盖日志
    • leader只能提交当前term的日志;不能提交前任日志
    • 当出现了leader与follower不一致的状况,leader强制follower复制本身的log

Followers 日志有效性检查:

  • AppendEntries RPC中还会携带前一条日志的惟一标识(prevTermId, prevLogIndex)
  • 递归推导

Followers 日志恢复:

  • Leader 将 nextIndex 递减并重发 AppendEntries,直到与 leader 日志一致

Raft协议的日志复制完整流程以下:

  • leader 将client的请求命令做为一条新的日志项写入日志。
  • leader 发送AppendEntries RPC 给follower 备份 该日志项。
  • follower收到leader的AppendEntries RPC,将该日志项记录到日志并反馈ack。
  • leader 收到 半数以上的follower 的ack,即认为消息发送成功
  • leader 将 该日志项 提交状态机(state machine)处理
  • leader 将执行结果返回给 client
  • leader 发送AppendEntries RPC 通知 follower 提交状态机
  • follower 收到AppendEntries RPC,follower判断该日志项是否已执行,若未执行则执行commitIndex以及以前的日志项。


-     安全性   -

Radt协议经过一系列的规范定义,保证了整个Raft机制的数据的顺序一致性。总体原则以下

  • 选举限制
    • 用投票规则的限制来组织日志不全的服务器赢得选举
      • RequestVote RPC限制规则: 拒绝日志没本身新的candidate
    • 领袖节点只能追加日志,不能重写或者删除日志
    • 日志条目只能从leader流向follower
  • 如何提交上一个任期的日志条目
    • 全程保持本身的任期号
  • 安全性论证
    • 领导人完整性原则(Leader Completeness)
      • 某指令在某个任期中存储成功,则保证存在于领袖该任期以后的记录中。
      • 不一样节点,某位置上日志相同,那么该位置以前的全部日志必定是相同的。
    • 状态机安全原则(State Machine Safety)
      • 若是节点将某一位置的日志应用到了状态机,那么其余节点在同一位置不能应用不一样的日志

经过上述的规范定义,咱们能够经过一些异常场景来突出Raft协议的安全性:

  • 追随者死机

当某台追随者死机时,全部给它的转发指令和拉票的消息都会因没有回应而失败,此时发送端会持续重送。当这台追随者引导从新加入集群,就会收到这些消息,追随者会从新回应,若是转发的指令已经写入,不会重复写入。

  • 领袖死机

领袖死机或断线时,每一个已存储指令一定已经写入到过半的服务器中,此时选举流程会让记录最完整的服务器胜选。其中一个因素是Raft候选人拉票时会揭露本身记录最新一笔的信息,若是服务器本身的记录比较新,就不会投票给候选人。

  • 超时期限和可用性

由于Raft引导选举是基于超时,使得超时期限的选择至为关键。若遵照算法的时限需求:广播时间 << 超时期限 << 平均故障间隔。这三个时间定义以下:

    • 广播时间:单一服务器发送消息给集群中每台服务器并获得回应的平均时间,须要测量获得。
    • 超时期限:发动选举的超时期限,由部署Raft集群的人选定。
    • 平均故障间隔:服务器发生故障之间的平均时间,能够测量或估计获得。

广播时间典型是 0.5ms 到 20ms,平均故障间隔一般是用周或月来计算的,因此能够将超时期限设在 10ms 到 500ms。


-     总结   -

本文整体介绍了Raft协议的三个核心概念及对应流程规范,经过这三个概念流程咱们能够很容易理解和实现Raft协议。Raft以容易理解著称,业界也涌现出不少 raft 实现,好比大名鼎鼎的 etcd, braft, tikv 等。也有不少知名的独立的Raft协议开源框架:

lhttps://github.com/sofastack/sofa-jraft/ 源于蚂蚁,java编写

lhttps://github.com/hashicorp/raft 源于hashicorp,go编写

lhttps://github.com/baidu/braft 源于百度,C++编写

lhttps://github.com/rabbitmq/ra 源于rabbitmq,Erlang编写


-     做者介绍    -

林淮川

毕业于西安交通大学;奈学教育《百万架构师训练营》讲师、企业级源码内源负责人,前大树金融高级架构师、技术委员会开创者、技术总监;前天阳宏业交易事业部技术主管;多年互联网金融行业(ToB)经验。



本文分享自微信公众号 - 川聊架构(gh_44ec4115d261)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索