共识:Paxos、Raft、ZAB

62 阅读 2140 字 · 约 8 分钟

数据分散在多个节点,消息不可靠,机器随时可能挂掉。现在你需要这些节点就一个值达成一致。

这不是什么抽象问题。选主——哪个节点当 leader。事务——一个操作跨多个节点,要么全做要么全不做。配置——集群配置一旦变更,所有节点要看到同一份。这些场景都在问同一件事:怎么让一群节点达成共识。

为什么需要共识

空间让数据分散,时间让顺序不明确,两个一叠加,共识问题就跑不掉。

单机上做决策很简单——代码逻辑是线性的。但多节点上没有全局信息,每台机器只看到自己那部分。更致命的是:消息可能延迟、可能丢失、可能乱序到达。节点本身可能挂了又起来。共识协议要在这几个约束下——节点会挂、消息不可靠、没有全局时钟——让多数节点就一个值达成一致。

FLP 定理(Fischer, Lynch, Paterson, 1985)说了一句残酷的话:在异步通信模型下,只要有一个节点可能挂掉,确定性共识就不可能。注意「确定性」三个字——它没说「概率性」不行。Paxos 和 Raft 正是利用随机超时加多数派投票,在工程上做到了足够可靠的共识。

Paxos:最经典的答案

Leslie Lamport 在 1989 年提出了 Paxos。论文本身就出了名——用了一个虚构的希腊岛议会来讲解算法,审稿人看了七年才发。

Paxos 的正确性毋庸置疑。它的核心思路:一个提案要获得通过,必须获得多数派的同意。如果两个提案都想通过,至少有一个节点同时投了两票——这个节点就能发现冲突,阻止第二个提案。这就是 Paxos 的「锁」:多数派保证了任意两个通过的提案,一定共享至少一个节点,而那个节点决定了谁先谁后。

但理解难度也是真的。Basic Paxos 是单值共识——一轮一轮地提案、投票、确认,效率不高。Multi-Paxos 把多轮合并,选出一个固定的 leader 连续提案,省掉了大部分投票轮次,实用性能才上来。

Google Chubby 是第一个大规模生产环境里的 Paxos 实现。它用 Paxos 做分布式锁,撑起了 Google 内部的很多基础设施。但 Chubby 把 Paxos 藏在内部,对外暴露的是一个简单的文件系统接口,也让更多团队看到共识协议是可以被封装好的。

Raft:拆成三个子问题

Diego Ongaro 在 2014 年提出了 Raft。他的核心贡献不是发明新算法——是重新设计了 Paxos 的表达方式。

Raft 把共识拆成三个独立子问题:Leader 选举、日志复制、安全性。Leader 选举:节点启动是 Follower,等不到心跳就变 Candidate 发起选举,拿到多数票变 Leader。日志复制:Leader 接收客户端的写请求,把日志条目复制到所有 Follower,多数确认后提交。安全性:保证 Leader 的日志一定是最新的——Candidate 投票时要比较日志新旧,日志旧的拿不到票。

拆分之后,每个子问题边界清楚。Paxos 很难理解是因为所有机制搅在一起,Raft 让工程师一个模块一个模块看懂。

etcd 和 Consul 都用 Raft。etcd 是 Kubernetes 的配置存储后端,所有集群状态变更都要走 Raft 的共识。Consul 用 Raft 做服务发现的配置一致性。这两个项目让 Raft 成了云原生生态里最普遍的共识协议。

ZAB:顺序优先

Zookeeper 用的协议叫 ZAB(Zookeeper Atomic Broadcast)。和 Raft 思路类似——也是 Leader 选举加日志复制——但 ZAB 更强调顺序。

Raft 和 ZAB 的差异在 Leader 切换时最明显。Raft 允许新 Leader 有未提交的旧日志——它把这些日志也复制到 Follower 然后提交。ZAB 不一样:新 Leader 必须先把所有 Follower 同步到自己最新的状态,确保新 Leader 的日志是完整的,再从新的起始点复制。这意味着 ZAB 的设计更偏「Follower 看到的顺序不跳跃」。

实际效果:Zookeeper 的 ZAB 保证了写操作的全局顺序,但读操作可能读到旧数据——这就是顺序一致性而非线性一致性。etcd 的 Raft 实现提供了线性一致性的读(需要额外一轮 Leader 确认),代价是读延迟略高。

Kafka 从 3.3 开始引入了 KRaft 模式——用自带的 Raft 实现替换掉 Zookeeper,把元数据管理和数据通道合在一个协议里。这是共识协议的实用化方向:不用单独维护一个 Zookeeper 集群。

共识的核心是多数派投票:任意两个通过的多数派必然共享节点;Paxos 数学最干净、Raft 工程最好懂、ZAB 顺序最严格

共识不是银弹

共识协议解决了「多数节点就一个值达成一致」,但代价是实打实的。写要等多数节点确认——延迟比单机高一个数量级。Leader 挂了要选举——选举窗口期不能写。节点数少——容忍少数节点挂;节点数多——延迟更大。

所以共识协议用在配置、选主、锁这些场景,数据量小但一致性要求高。数据量大的路径——比如业务数据的复制——通常走异步复制加最终一致性,不靠共识。

小结

Paxos 提出了共识的核心思路:多数派投票。Raft 把 Paxos 拆成三个独立子问题,可理解性好了至少一个数量级。ZAB 更强调顺序,牺牲了部分一致性换取了更好的顺序保证。

三个协议不是竞争关系——是同一个问题在不同时期的理解和工程化。Paxos 是数学上最干净的,Raft 是工程上最好懂的,ZAB 是顺序上最严格的。它们共同回答了一个问题:让一群不可靠的节点,产生一个可靠的结论。