Skip to content
Go back

CAP定理、BASE理论与Raft共识算法——分布式理论的基石

CAP、BASE、Raft:分布式理论的三大基石

一句话结论(30s)

CAP 给出理论边界(网络分区发生时一致性/可用性不可兼得),BASE 是它的工程落地(用最终一致性换可用),Raft 是实现”一致性”这一侧的可理解共识算法——因为分布式系统逃不开分区,所以必须在”强一致但可能拒绝服务”和”高可用但可能读到旧数据”之间做选择,Raft 负责把前者做扎实。

核心原理(2min)

底层深入(5-10min)

CAP 定理

分布式系统在遇到网络分区(Partition)时,只能在一致性(Consistency)和可用性(Availability)之间二选一:

没有 P 就没有 CAP 的抉择。 没有网络分区时,C 和 A 可以同时满足。一旦网络断开,系统必须在”返回可能不一致的旧数据(选 A)“和”拒绝请求等待分区恢复(选 C)“之间选一个。

ZooKeeper 选 CP(分区时宁可拒绝请求也保证一致)。Eureka 选 AP(分区时宁可返回旧数据也保证可用)。

思考:为什么 CAP 只能三选二,不能三全? 因为分区(P)是物理现实——交换机宕机、机房断网、脑裂,这些故障你无法消除,只能”容忍”。P 一旦发生,C 和 A 就互相冲突:想保证 A(每个请求都有响应),就得让分到另一半的节点继续应答,可那半边拿不到最新数据,必然违背 C;想保证 C,就得等分区恢复、拒绝那半边的写请求,又违背 A。所以真正的问题是”分区发生时,你要牺牲 C 还是 A”,P 本身没得选——“三选二”的准确含义是 P 必须保留、只在 C 和 A 之间取舍。

BASE 理论:CAP 的工程化落地

强一致性(ACID)在分布式系统中代价太高。BASE 是 CAP 的工程折中:

RocketMQ 事务消息就是 BASE 的经典实践——先发 Half Message(不可见),执行本地事务成功才 Commit(最终一致),中间状态对消费者不可见。

思考:BASE 为什么能”落地”,CAP 却只能当理论? 因为 CAP 是”是非题”(要么 C 要么 A),而 BASE 是”程度题”(允许短暂不一致,但最终会收敛一致)。生产系统几乎没人能承受永久强一致的成本——一次跨机房同步要几十毫秒,全部串行化等于把分布式退化成单机。BASE 用”最终一致”这个时间维度上的让步换来了可用性和吞吐,所以能被工程采纳。RocketMQ 的 Half Message 正是把”中间状态”隔离在消费者视野之外,让最终一致对业务无感。

Raft:比 Paxos 更容易理解的共识算法

Raft 把共识拆成三个子问题:

Leader 选举

所有节点以 Follower 启动,超时未收到 Leader 心跳 → 变为 Candidate → 发送 RequestVote → 获得多数票 → 成为 Leader。

选主条件:获得超过半数节点的投票(>= N/2 + 1)。3 节点容忍 1 故障,5 节点容忍 2 故障。Candidate 的 term 必须 >= 其他节点的 term,lastLogIndex 越新越优先。

思考:为什么是”过半票”而不是”全票”? 因为全票要求任何一个节点失联就无法选主,系统可用性极差;而”过半”保证同一时刻最多只有一个候选人能拿到多数票——两个候选人的票集必然有交集,而一个节点在一个 term 里只能投一票,从数学上杜绝了双主。这也顺带解释了容错公式:N 个节点最多容忍 floor(N/2) 个故障,再多就凑不齐多数派了。

日志复制

Leader 收到客户端写请求:
  1. 追加到本地日志(uncommitted)
  2. 并行发送 AppendEntries 给所有 Followers
  3. 多数 Follower 回复 ACK → 提交(committed)
  4. 通知所有 Follower 提交 → 响应客户端

任何节点挂掉、网络分区,只要 Leader 存活且有半数以上 Follower 在线,系统正常工作。Leader 挂掉 → 重新选举。

思考:为什么日志要”多数派 ACK”才算提交,而不是 Leader 自己写成功就算? 因为 Leader 随时可能宕机,若只有它自己落盘就返回成功,这条日志在它死后就”消失”了,而它之前已经对客户端承诺过——违背了”已提交的日志永不丢失”这条底线。多数派 ACK 保证至少有一个 Follower 也持有这条日志,即使 Leader 挂掉,新 Leader 一定在多数派里(选主也要求多数票),日志得以延续。多数派是 Raft 一致性的数学根基。

安全性

Raft 保证:

Raft vs Paxos

Paxos 是理论框架(单次决议),Multi-Paxos 是 Paxos 的工程实现但理解困难。Raft 把问题分解为”选主+日志复制+安全”三个独立模块,每个模块独立可理解,比 Paxos 的学习门槛低一个数量级。RocketMQ DLedger、etcd、Consul、TiKV 全部基于 Raft。

思考:Raft 和 Paxos 到底差在哪? 一句话:Paxos 给你一组”公理式”原语(prepare/accept),完整系统要你自己推导;Raft 直接把”系统该怎么运转”拆成三个具体模块,照着实现就行。Paxos 难在”一次决议”和”连续决议(Multi-Paxos)“之间有巨大鸿沟,工程上还要自己补选主、日志压缩、成员变更这些论文没写清楚的东西;Raft 把这些打包成可理解的完整设计,所以 etcd/Consul/TiKV 宁愿用它。结论是二者正确性等价,但 Raft 的”可工程性”让它成为事实标准。

总结

CAP 定义理论边界(P 发生时 C/A 二选一),BASE 给出工程折中(最终一致性替代强一致性),Raft 实现共识(Leader 选举 + 多数派日志复制)。三者是分布式系统设计的完整理论栈。

章末提问

Q1:CAP 里的 P 到底是什么意思?是不是系统只能满足三个里的两个? 结论先行:P 是”系统能否容忍网络分区”的能力,不是可选开关;准确说法是”分区发生时,C 和 A 只能二选一”。因为网络分区是物理故障,无法避免也无法”选择不要”,你只能选择容忍它,所以 P 永远要保留;真正的取舍发生在 C 和 A 之间——没有分区时 C、A 本来就同时成立,所以”三选二”是通俗但不严谨的表述。

Q2:ZooKeeper 为什么选 CP,它牺牲可用性体现在哪里? 结论先行:体现在集群选主期间(通常几十秒到几分钟)整个集群拒绝所有读写请求。因为 ZooKeeper 依赖 Leader 处理所有写、且要求过半节点同步才返回,一旦 Leader 挂掉或发生分区、凑不齐多数派,它宁可让服务不可用也不返回可能不一致的数据。代价就是这段时间的可用性为零,这是 CP 系统的典型表现。

Q3:BASE 的”最终一致”和”强一致”到底哪个好,能不能说强一致更优? 结论先行:不能,二者是取舍不是高低,取决于业务能否容忍短暂不一致。因为强一致要付出更高延迟和更低可用性(跨机房同步、多数派确认),对下单、扣库存这类”钱相关”业务值得;但点赞数、浏览计数这类允许秒级收敛的场景,强一致是过度设计,最终一致能用十分之一的成本拿到近似的体验。选型的判据是”读到旧数据会造成多大损失”。


Share this post on:

Previous Post
LSM树——写多读少场景下的存储引擎王者
Next Post
高楼扔鸡蛋——动态规划的逆向思维