vlambda博客
学习文章列表

raft-基本术语介绍

raft是一个管理复制日志的算法,通过选举一个leader,并赋予其足够的权力来管理日志的复制。

  • 选举leader

  • leader接受client的请求,并将其写入本地的日志

  • 并行复制该日志到其他节点

  • 得到大多数节点成功写入日志的回应后,leader将该日志应用到状态机(通常由上次服务实现),并响应给client

通过单一的leader进行管理,raft算法可以简化日志复制的管理,同时整个集群的数据流也很简单:由leader->follower。

有了leader这个路子,raft将共识算法按照分而治之的套路分为了几个相对无关的子问题:

  • leader选主

  • 日志复制

  • 保证上述问题的一些安全限制

    • 在一个给定的term内只能有一个leader

    • leader除了追加log外,绝不会覆盖或者删除它的log

    • 如果两个log包含相同的index和term,在这个index之前的所有log也保证一致

    • 如果log在一个给定的term中被提交了,那这个log必定出现在所有更大的term任期的leader中

    • 如果一个节点在给定的index应用了一条log,其他server必定不会在该index应用不同的log


role

不管是选主还是日志复制都需要大数据节点达成一致,因此raft通常的节点数目为3个或者5个,所有节点在给定时间内都处于以下角色之一:

  • leader:处理client请求,复制日志

  • follower:被动接受leader或者candidate的请求

  • candidate:主要用于选举阶段,当接收到大多数投票(包括自己)的回应后就转为leader


term

raft将时间分为任意长度的任期(term),term是一个连续的整数,每次发起选主就递增;每个候选者在成为leader之后都会记录它当前的term,通过term在后续的通信过程中能根据该值的大小做一些逻辑:

  • 发现过期的leader(比如网络分区)

  • candidate或者leader发现自己的term过期了,会转化为follower

  • 如果一个节点收到过期的term,会拒绝该请求


state,以下状态在raft的选举和日志复制过程中会逐步体现

  • 需要在所有角色的server上持久化

    • currentTerm,当前可以看到的最新的term,初始化为0,单调递增

    • votedFor,接收到投票的候选者id,如果没有投给其他server则为null

    • log[], 日志条目,每个条目包含两个部分:需要被状态机执行的指令;接受该条目时的leader的term(第一个条目的index为1)

  • 在所有角色的server上变化的状态

    • commitIndex,已知最大的被commited(还没有被应用到状态机)的log索引,初始化为0,单调递增

    • lastApplied,已知最大的被applied(被应用到状态机)的log的索引,初始化为0,单调递增

  • 在leader上变化的状态(选举后需要重新初始化)

    • nextIndex[],每个需要复制给follower的下一条log的index,初始化为leader存储的log[]状态中的index+1

    • matchIndex[],每个follower已经完成复制的log的最大index,初始化为0,单调递增


所有的server之间通信都是通过rpc方式完成,基本上的raft算法只要求RequestVote和AppendEntries两个rpc,其中AppendEntries也可以作为心跳来用。