相同的初始状态 + 相同的输入 = 相同的结束状态
在 Raft 中,lead 将客户端请求(command)封装到一个个 log entry 中,将这些 log entries 复制到所有 follow 节点,然后大家按相同顺序应用 log entries 中的 command,根据复制状态机的理论,大家的结束状态肯定是一致的。
使用共识算法,就是为了实现复制状态机,从而实现高可用。
在任何时刻,每一个服务器节点都处于 leader、follower 或 candidate 这三个状态之一。
相比于 Paxos,Raft 不用考虑状态之间的共存和相互影响,只用考虑状态的转化,极大地简化了算法的实现。
Raft 算法将时间划分成为任意不同长度的任期(term)。任期用连续的数字进行表示。每一个任期的开始都是一次选举(election),一个或多个候选人会试图成为领导人。
Raft 算法中服务器节点之间通信使用远程过程调用(RPC),并且基本的一致性算法只需要两种类型的 RPC。
服务器之间通信的时候会交换当前任期号;如果一个服务器上的 currentTerm 比其他的小,就会更新为较大的那个。如果一个 candidate 或者 leader 发现自己的任期号过期了,它会立即回到 follower 状态。如果一个节点收到一个包含过期的任期号的请求,会直接拒绝这个请求。
对于没有成为 cadidate 的 follower 节点,对于同一个任期,会按照先来先得的原则投出选票。
Leader 接收到客户端的指令后,会把指令作为一个新的条目追加到日志中去。
一条日志需要具有三个信息:
Leader 并行发送 AppendEntries RPC 给 follower,让它们复制该条目。当该条目被超过半数的 follower 复制后,leader 就可以在本地执行该指令并把结果返回客户端。
我们把本地执行指令,也就是 leader 应用日志与状态机这一步,称作提交。
Raft 的一致性检查:leader 在每一个发往 follower 的追加条目 RPC 中,会放入前一个日志条目的索引位置和任期号,如果 follower 在它的日志中找不到前一个日志,那么它就会拒绝此日志,leader 收到 follower 的拒绝后,会发送前一个日志
3.如果 leader 崩溃,那么 leader 可能已经复制了日志到部分 follower 但还没提交,而选出的新 leader 不具备这些日志,这样就产生冲突。在这种情况下,leader 通过强制 follower 复制它的日志来解决不一致的问题
对于 follower,如果 leaderCommit > commitIndex,那么把 commitIndex 设为 min(leaderCommit,index of last new entry)
在需要改变集群配置的时候(如增减节点、替换宕机的机器或者改变复制的程度),Raft可以进行配置变更自动化。
集群先切换到一个过渡的配置,称之为联合一致(joint consensus)
第一阶段:leader发起Cold,new , 使整个集群进入联合一致状态。这时,所有RPC都要在新旧两个配置中都达到大多数才算成功。
第二阶段:leader 发起Cnew,使整个集群进入新配置状态。这时,所有RPC只要在新配置中达到大多数才算成功。
根据需要同步的数据量按大小进行分类,分别适合不同类型的共识算法。
共识算法特性:
Raft区别于其他共识算法的特性:
一个节点当选leader后,立刻发送一个自己当前任期的空日志体的AppendEntries RPC。这样,就可以把之前任期内满足提交条件的日志都提交了。
目前大部分应用于生产系统的raft算法,都是启用no-op的。
随着raft集群的不断运行,各状态机上的log也在不断地累积,我们需要一个机制来安全地清理状态机上的log。
Raft采用了快照技术:每个节点在达到一定条件后,可以把当前日志中的命令都写入自己的快照,然后就可以把已经并入快照的日志都删除了。
leader如何同步日志给落后很多的follower?
raft的策略是直接向follower发送自己的快照
ParrallerRaft是阿里云原生数据库PolarDB的底层文件PolarFS对Raft的一种优化的实现
Raft
Raft一致性算法笔记 - 简书