前言
There is only one consensus protocol, and that’s Paxos. ——Mike Burrows(Google Chubby)
Overview
Paxos 和 Raft 的共识方式是类似的,大多数是术语的区别,比如对于 Multi-Raft 而言,大致可以分为三个层,Client,Server,Raft。
- Client 层给请求包一个唯一 id,扔到对应 Raft Group Server 层的 Leader 节点;
- Server 层是处理请求的地方,需要和 Raft 层交互,具体而言,Server 层需要将 Client 的请求发送到 Raft 层进行共识,多数派共识之后这个 Raft Group 的不同 Server 都会执行相同的请求,但是由 Leader 返回结果;
- Raft 层通过领导人选举、心跳、日志复制进行共识,日志过多时还能进行快照压缩;其中,Raft 的 leader 对应 Paxos 的 Proposer,会分配一个 rnd 并发起一次 Paxos 共识,Paxos 还有 Acceptor 和 Learner。
- Raft 的 Term 还被 Paxos 称作 views, ballot numbers, proposal numbers, round numbers。
- Raft 的选举的过程有些类似于 Classic Paxos 的 phase-1。
- Raft Leader 的日志复制则类似于 Classic Paxos 的 phase-2。
Classic Paxos phase-1
当 Paxos 的 Proposer 向 Acceptor 发送一个共识的请求时,如果请求中的 rnd 比 Acceptor 的 last_rnd 小,则拒绝共识该请求(返回自己的 last_rnd 和 value);反之,则将 last_rnd 设置为 rnd,从此 Acceptor 只接受 last_rnd 的 phase-2 请求。所以 rnd 大的请求会覆盖 rnd 小的请求。
当 Proposer 收到 Quorum(可以简单理解为多数派)后,如果收到了 value 和 last_rnd,并且 last_rnd 比自己的大,直接退出;如果比自己的小,说明已经有其他的 Proposer 正在运行,那么需要在 不修改已存在的值的前提下 从所有 Acceptor 中选择最大的 vrnd 对应的 value 进行 phase-2。
Classic Paxos phase-2
Acceptor 收到 Proposer 后,如果 rnd 不等于 last_rnd 则退出,否则将 value 写入本地。
Classic Paxos phase-3
Acceptor 发送 phase-3 到所有的 learner,让其知道一个请求被确定了,多数场合下 proposer 也是 learner。
Multi-Paxos
Classic Paxos 没有 leader,每个请求的共识都由 Proposer 提出,在高并发的时候可能会有活锁问题,Multi-Paxos 引入了 Leader,可以稳定地进行提案, 并且会将多个请求的 phase-1 合并成一次 rpc,并且仅通过一次 phase-2 完成最终的共识。
Fast-Paxos
直接发送 phase-2,并且 rnd 为 0,保证能够安全回退为 Classic Paxos,Acceptor 在 value 为空的时候才接受 Fast-Paxos,但是在并发写入的时候,Fast-Quorum 的节点数需要大于 3/4,原因是 Fast-Quorum 的 Acceptor 在 Classic-Quorum 中必须超过半数,才不会导致退化为 Classic-Paxos 重试的时候选择一个错误的 value。
Multi-Paxos 与 Raft 的不同
diff | Paxos | Raft |
---|---|---|
确保只有一个 Leader 的机制 | 只有 t mod n = s 的时候(t 为当前任期,n 为集群节点数,s 为节点 id)才能变成 candidate | 每轮选票只能投给一个 candidate |
怎么确保成为新的 Leader 包含了所有的 log entries | candidate 收到了 quorum 的回复后,从回复中添加最新的日志 | 只有包含最新日志的 candidate 才会被大多数节点承认为 leader |
怎么确保 leader 安全地 commit 了之前任期的日志 | 新的 leader 会将未 commit 日志的任期更新为当前 term,并继续复制 | 新的 leader 不会改变日志的任期,当随后的日志(noop entry)被多数节点确认后才算是 commit |