想象你这样经营一家奶茶连锁店。单店时代,老板和店员共用一块黑板,价格永远不会分裂。但当分店开到几十家、跨越几个城市,总店每天早晨都必须打电话向每间分店广播今日价格。暴雨天,某条电话线断了——城东分店联系不上总店,顾客照样排队要买奶茶,店员盯着黑板上的旧价格心里打鼓:这个价格还作数吗? 分布式系统面对的是同一个问题:多个节点(分店)通过网络(电话)协同工作,而网络恰恰是最不可靠的部分。CAP 定理就是这场雨的天气预报,它告诉你:当电话线不可避免地断开时,你必须在“所有分店黑板价格一致”和“每个分店都能立刻营业”之间做一个艰难的取舍。一致性(Consistency)、可用性(Availability)、分区容错(Partition tolerance)——这三个概念构成了所有分布式系统设计的底层坐标。 本文将从定理的起源、三大属性的精确定义、形式化证明,讲到 CP 与 AP 在真实工程中的取舍策略,最后给出架构师的生产决策框架。读完之后,你会发现 ZooKeeper 为什么宁可拒绝请求也不给旧数据、DynamoDB 为什么愿意让你读到延迟数据——种种“怪脾气”,都能在 CAP 的框架下找到合理解释。

岗位关联

CAP 定理是分布式架构师的“第一性原理”。理解它,你才能真正看懂主流中间件的行为差异,在业务设计、故障排查和架构评审中做出不可替代的专业判断。

目录
  1. 可视化演示
  2. 定理起源
  3. 三大属性
  4. 定理表述
  5. 常见误解
  6. CP系统策略
  7. AP系统策略
  8. 工程决策
  9. 演进方向
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示CAP三角权衡关系、网络分区下CP与AP系统行为差异及实际系统性能对比。

本节配有交互动效(进入视口后自动加载,约 3KB)。

CAP三角权衡关系 C一致性:所有节点同时看到相同数据 P分区容错:网络分区时系统继续运行 CAP只能选2/3,P不可放弃 分布式系统必须选择CP或AP

定理起源

你从一家奶茶店起步。单店时代,老板和店员面对面,黑板上的价格永远不会出分歧。后来开到十家、一百家分店,总店每天早晨要打电话给每一家分店广播今日价格。某天暴雨,一条电话线断了——总店联系不上城东分店,可城东分店还在开门营业。这就是分布式系统的出生证明:当系统从一台机器变成多台机器,“协调”本身就是最难的问题。

所有分布式系统的核心矛盾都是:多个节点通过网络协作,而网络不可靠。2000 年,Eric Brewer 在 PODC 会议上提出一个猜想:分布式系统的一致性(Consistency)、可用性(Availability)、分区容错(Partition tolerance)三者不可能同时满足。这个猜想立刻引起轰动,因为当时业界已经开始用两阶段提交(2PC)和多副本复制来解决一致性问题,但从来没有人给出过理论边界。

2002 年,Seth Gilbert 和 Nancy Lynch 发表论文,用异步通信模型严格证明了该猜想。论文的核心贡献不是提出“三选二”的口号,而是把“分区发生时系统如何应对”这个问题正式摆到了架构师面前:只要系统由多个通过网络协作的节点构成,网络分区(消息无法投递)的概率就不是零,你必须提前想好退路。

回想奶茶店,单店时代的幸福感恰恰因为不需要打电话。一旦跨城开店,“电话断线怎么办”就成了开店的必答题。CAP 定理就是给你画清楚“雨天能做什么选择”的那张地图——它不是诅咒,而是帮你把最坏情况变成可计算的选择题。

三大属性

把三个属性比作奶茶店的三个承诺。第一面招牌“黑板同步”(C):任何分店黑板上写的价格都与总店完全一致;第二面招牌“有问必答”(A):顾客任何时候进店,店员都能立刻报出价格、做好奶茶;第三面招牌“断线营业”(P):即使部分电话线断了,整个连锁体系还能按某种规则运转。

C(一致性)在 CAP 中专指线性一致性(linearizability):所有副本表现得像只有一个副本,任何一个写操作完成后,后续所有读操作都必须读到这个新值。它衡量的是“你的数据在全局时间轴上是否只有一个版本”。A(可用性)要求每个读写请求都在有限时间内收到非错误响应——注意“非错误响应”很关键,一直等待或直接抛异常都不算可用。P(分区容错)指系统在网络分区(节点间消息丢失、延迟、无法投递)时仍能继续提供服务,它不是一种可选的“功能”,而是分布式系统必须面对的环境事实。

三者关系可以这样理解:C 和 A 是业务可感知的质量指标,P 是环境硬约束。就像奶茶店,C 和 A 是顾客能直接感受到的服务质量,而电话线断不断不由你决定。在单店时代三者天然统一,一旦多店联网,C 和 A 之间就开始出现张力。

奶茶店挂出三面招牌很容易,难的是暴雨天三个承诺同时兑现——店面设计可以很漂亮,但天气不归你管。这正是接下来定理要回答的问题:当环境约束出现时,哪两个承诺还能同时守住?

定理表述

暴雨天,电话线断了,店员的处境很简单:要么告诉顾客“稍等,我打电话问总店”——但电话打不通,顾客等得不耐烦,可用性受损;要么按自己黑板上的旧价格先卖——但很可能与总店新价格不一致,一致性受损。你不可能一边“向总店确认价格”一边“立刻回答顾客”。

CAP 定理把这场雨形式化:在异步网络模型中,消息可能延迟或丢失。把系统分成两组 G₁ 和 G₂,中间网络断开。客户端向 G₁ 写入值 v,此时若 G₂ 中的读请求立刻响应,它无法获得 v(消息过不去),一致性被打破;若 G₂ 必须等 v 到达才响应,等待时间无穷,可用性被打破。这就是反证法的核心矛盾。由此得出:

定理把奶茶店的困境变成了数学:只要电话线可能断,就必须在“等总店消息”和“先按旧价格卖”之间选一条路。想清楚这个前提,后面所有工程策略都只是“选哪条路、怎么走好”的问题。

C∧A⇒¬P\displaystyle C \wedge A \Rightarrow \neg P
通俗地说:如果你要求“永远一致”且“永远可用”,那网络就永远不能断——这在真实分布式系统中做不到,所以分区发生时,一致性和可用性只能二选一,即 P ⇒ (C ⊕ A)。
  1. C ∧ A同时满足一致性与可用性,即所有节点永远返回最新值,且所有请求都能及时响应。
    C∧AC \wedge A
  2. ⇒(蕴含)逻辑上“如果前者成立,那么后者必然成立”——这是一条硬性推导,不是经验总结。
    ⇒\Rightarrow
  3. ¬P对分区容错的否定,等价于“网络永远不会发生分区”。
    ¬P\neg P
  4. P ⇒ (C ⊕ A)等价变形。只要分区会发生,面对分区时 C 与 A 就只能保全一个,⊕ 表示互斥二选一。
    P⇒(C⊕A)P \Rightarrow (C \oplus A)

常见误解

“三选二”这句话流传太广,有人真以为 CAP 是三张牌任选两张,还有人美滋滋地选了"CA"——他们觉得只要把电话线换成光纤就不会断。可现实是:只要奶茶店开在不同城市,暴雨、施工、设备故障就会轮流来,电话线不可能永远不断。

这里需要澄清三个流行的误读。第一,P 不能被“放弃”。P 不是功能开关,而是环境事实;CA 只在“永远无分区”的理想模型中成立。真实分布式系统只要有多节点、有网络,分区概率就不是零,所以设计默认前提是 P。第二,C 与 A 不是全有全无的硬开关。权衡发生在“分区期间”这个时间窗里:无分区时两者可以同时满足;分区时可以选择拒绝部分请求保一致,也可以继续服务容忍陈旧,还可以按请求粒度混合处理。第三,CAP 不是系统级的一锤子买卖。一个大型系统内部,不同数据、不同操作可以走不同策略——核心链路用强一致,边缘功能用最终一致,用一致性级别、路由规则、超时策略组合出大量中间状态。

这些误解的共同根源,是把一个描述“极限情况”的定理当成了日常配置手册。CAP 更像交通事故安全气囊的测试标准——平时不触发,但触发时它的存在决定了乘客的生死。三张牌的说法只能帮你记住名字,不能帮你做设计。

聪明的奶茶店主不会问“我们店是纪律严明型还是灵活应变型”,而是问“哪类产品线下雨天必须保持价格统一,哪类可以事后再调”。带着这个问题,我们来看两种主流策略。

CP系统策略

“宁可错停,不可错卖”是 CP 的座右铭。城东分店电话断了,总店立刻远程把它锁死:门口挂出“暂停营业”。顾客虽然吃闭门羹,但一旦进店,黑板上的价格绝对和总店一致,没有坑。

CP 系统通过三类机制实现这个承诺。一是多数派确认(quorum):写入必须获得超过半数的副本确认才返回成功,哪怕一个副本失联,只要还剩大多数,写入仍可完成。二是选主机制:集群选举唯一 leader,所有读写都走 leader;分区后旧 leader 失联时多数派重新选主,少数派丧失服务资格。三是拒绝降级:不满足条件的请求直接返回错误或长时间等待,绝不返回可能过期的数据。ZooKeeper 的 ZAB、etcd 的 Raft、HBase、MongoDB 配置 writeConcern: majority 后,都属于这类系统。它们的共性保证是:你读到的值,一定是已经被大多数节点确认过的值。

CP 的代价是分区期间可用性下降:少数派节点拒绝读写,客户端会看到连接失败、超时或异常。所以 CP 系统必须配套客户端重试、快速失败和熔断策略。ZooKeeper 生产事故中常见的问题,就是分区时客户端在少数派节点上长时间阻塞,最终全部超时雪崩——这提醒我们,CP 不是“挂个招牌就完事”,而是需要客户端和服务端共同遵守纪律。

挂“暂停营业”的店也许会损失这半天流水,但招牌信誉保住了。对支付、库存这类业务,信誉比流水值钱——这正是 CP 系统的生存哲学。

AP系统策略

另一家奶茶店选择“先营业,后对账”:城东分店断线期间照常卖茶,按自己黑板上的旧价格成交,每笔都记在账本上。暴雨过后电话恢复,总店把新价格发过来,城东店把账本回传,差价多退少补,所有分店重新统一。顾客体验流畅,只是个别顾客可能买贵或买便宜了几毛钱。

AP 系统的核心思想是最终一致性(eventual consistency):分区期间允许每个分区独立读写,造成短暂的不一致;分区结束后通过机制自动收敛。其形式化描述是:设节点 i 和 j 存储同一份数据的副本,若分区结束后停止新的写入,它们的值会趋同:

Cassandra、DynamoDB(默认多活配置)、CouchDB 以及 Eureka(服务发现的 AP 选择)都是典型的 AP 系统。它们的代价是可能读到旧数据、并发写会产生冲突。把“先营业后对账”做成制度,靠的正是版本号和合并规则——这在工程上比 CP 的“暂停营业”更复杂,也更考验业务容忍度。

lim⁡t→∞(Vi(t)−Vj(t))=0\displaystyle \lim_{t \to \infty} \big( V_i(t) - V_j(t) \big) = 0
这个公式描述的是“收敛”:两副本的数值差异随时间推移趋向于零。收敛依赖版本追踪(版本号、时间戳、向量时钟)和冲突合并(LWW 最后写入者胜出、CRDT 无冲突复制类型、业务定制合并规则)两类机制。
  1. Vi(t) 与 Vj(t)节点 i 和节点 j 在时刻 t 存储的同一数据的副本值。
    Vi(t), Vj(t)V_i(t), \ V_j(t)
  2. lim(极限)当时间 t 趋向无穷大时观察结果——表示“分区结束并持续同步足够久之后”。
    lim⁡t→∞\lim_{t \to \infty}
  3. 差值为零两副本的值最终完全一致,差异消失,系统达到收敛状态。
    Vi(t)−Vj(t)=0V_i(t) - V_j(t) = 0

工程决策

成熟奶茶店不会全店一个策略:招牌芋圆奶茶的价格全国统一、绝不偏差,这是 CP;季节限定新品允许分店推出“本地特惠”,事后对账,这是 AP。一条街上的连锁店,两类产品同时存在。

架构师做 CAP 决策时看四个维度。第一,数据性质:资金、库存、订单、实名信息错误代价高,选 CP;点赞数、浏览数、推荐位短暂偏差无感,选 AP。第二,业务容忍度:能不能接受读到旧值?支付页面余额必须准,feed 流里少一条新鲜事无妨。第三,故障影响面:核心链路(下单、扣款)用强一致 + 多副本;非核心链路(通知、统计)用最终一致 + 异步。第四,降级预案:平时走 AP 的系统在极端场景可临时切换为“CP 式拒写”以保护数据;平时走 CP 的系统也要设计“本地缓存兜底”,避免整个核心链路被拖死。

生产复盘案例:某电商大促时订单中心走 CP(MySQL 主从 + 分布式事务),购物车和优惠券展示走 AP(Redis 缓存 + 异步对账)。一次机房光纤抖动导致订单写入短暂失败,但因为熔断和重试机制,最终没有资金差错;而非核心的购物车短暂显示了旧优惠券,用户可感知但无资损。这次复盘的关键结论是:CP 保护了钱,AP 保住了体验,两者各司其职。

好的连锁店管理手册会写清楚:“哪些品类必须全国统价,哪些品类可以本地灵活。”CAP 决策的本质,就是把这条“分数线”画对。

演进方向

电话线从铜线变成光纤再变成 5G,越来越稳,但雨季和施工队永远存在。奶茶店主真正要做的不是祈祷不断线,而是把“断线时的柜台操作手册”提前写好。

CAP 定理只回答了分区发生时的取舍,却遗漏了“无分区时”的权衡。PACELC 模型补全了这块拼图:

与此同时,共识算法(Raft、ZAB、Paxos)让 CP 系统实现变得工程化,选主、日志复制、快照等细节成为可靠基础设施的标准件;多活架构让每个区域自治(AP 式)加全局同步(CP 式)混合;边缘计算在本地保留副本,减少跨区请求,降低分区对用户体验的影响。但无论技术怎样演进,只要网络物理上不可靠,权衡逻辑就不会消失。

奶茶店的管理从“老板一个人说了算”进化成“一套自动化的沟通仪式”,但雨天预案永远写在使用手册第一页。CAP 定理教你的不是选边站,而是把“哪边更重要”想清楚再站。

PACELC: P→(A vs C),¬P→(L vs C)\displaystyle \text{PACELC: } P \rightarrow (A \text{ vs } C), \quad \neg P \rightarrow (L \text{ vs } C)
意思是:如果发生分区(P),在可用性(A)与一致性(C)之间取舍;如果没有分区(¬P),在延迟(L)与一致性(C)之间取舍。这解释了为什么很多系统平时也愿意牺牲一点一致性换低延迟,比如缓存加异步刷新。
  1. P → (A vs C)分区发生时,第一优先级的决策是在可用性与一致性之间选择,这与 CAP 定理一致。
    P→(A vs C)P \rightarrow (A \text{ vs } C)
  2. ¬P → (L vs C)没有分区时,决策转向延迟(Latency)与一致性之间的权衡——强一致往往需要跨节点确认,延迟更高。
    ¬P→(L vs C)\neg P \rightarrow (L \text{ vs } C)

AI 应用场景

电商订单库存系统设计

阶段:系统架构设计 / 数据一致性保障

解决的问题:下单、扣库存、支付链路如果读到过期数据,会导致超卖和金额错误。传统做法是数据库行锁加分布式事务,所有节点等待多数派确认,写入慢但正确;若盲目追求高可用而放弃强一致,则可能造成资损。

具体案例:某交易系统在机房光纤抖动时,订单中心主动返回 503 而非乱扣款,用户重试后成功;库存服务保持 CP,避免超卖;同时优惠券展示走 AP,短暂显示旧券但不影响资损。正是“核心链路 CP、非核心链路 AP”的混合设计,让一次物理故障没有演变成资金事故。

社交信息流与点赞计数

阶段:数据写入路径设计

解决的问题:朋友圈点赞、浏览数每秒几十万次写入,要求每个请求立刻成功。传统强一致方案会因锁和多数派确认带来高延迟和请求丢失,用户体感变差。

具体案例:某内容平台用 AP 思路:点赞先写本地缓存,后台异步批量同步,最终一致;热门视频的点赞数短暂偏差可接受,但视频的上架/下架状态走 CP,保证审核结果全局生效。通过把“展示型数据”和“状态型数据”分流,既保住了体验,也保住了底线。

微服务注册中心选型

阶段:基础设施选型

解决的问题:注册中心负责服务发现,每个服务上线或下线都要通知其他服务。选 CP(etcd/ZooKeeper),分区时注册中心可能拒绝服务,但不会把“半死不活的服务”发给调用方;选 AP(Eureka),目录始终可用,但调用方可能请求到已下线的实例。

具体案例:某公司把核心交易链路的注册中心用 etcd(CP),保证路由信息绝对可靠;把非核心的配置读取用 Nacos(支持 AP 模式),保证配置中心随时可读。两条链路都通过心跳和重试机制兜底,既避免了单点,也把分区影响隔离在非核心范围。

Python 演示

python64 行
"""CAP tradeoff simulator: partition scenario demo."""  class Node:    def __init__(self, name, value=0, version=0):        self.name = name        self.value = value        self.version = version        self.partition = 0     def write(self, value):        self.value = value        self.version += 1  class KVStore:    def __init__(self, node_names):        self.nodes = [Node(n) for n in node_names]        self.majority = len(self.nodes) // 2 + 1     def set_partition(self, partitions):        for node in self.nodes:            node.partition = partitions.get(node.name, 0)     def reachable(self, node):        return [n for n in self.nodes if n.partition == node.partition]     def write_cp(self, node, value):        peers = self.reachable(node)        if len(peers) < self.majority:            return False, "minority cannot confirm"        for n in peers:            n.write(value)        return True, "majority confirmed"     def write_ap(self, node, value):        node.write(value)        return True, "local write ok"     def read_all(self):        return {n.name: (n.value, n.version) for n in self.nodes}  def main():    store = KVStore(["A", "B", "C"])    print("normal state:", store.read_all())    store.write_cp(store.nodes[0], 1)    print("write 1 ok:", store.read_all())     store.set_partition({"A": 1, "B": 1, "C": 2})    ok, msg = store.write_cp(store.nodes[0], 2)    print("CP write under partition:", ok, msg)    ok, msg = store.write_ap(store.nodes[2], 3)    print("AP write under partition:", ok, msg)    print("divided state:", store.read_all())     store.set_partition({"A": 1, "B": 1, "C": 1})    ok, msg = store.write_cp(store.nodes[2], 2)    print("merge catch-up write:", ok, msg)    print("final state:", store.read_all())  if __name__ == "__main__":    main()
目的:模拟一个三副本 KV 存储在“正常 → 网络分区 → 恢复”过程中的 CP 与 AP 行为差异,直观展示多数派确认和本地写入的取舍。
  1. self.majority = len(self.nodes) // 2 + 1计算多数派门槛,3 个节点需要 2 个确认才算写入成功。
  2. def set_partition(self, partitions)模拟网络分区,把每个节点划入不同的分区组。
  3. def reachable(self, node)找出与指定节点同分区的“可达副本”,模拟断线后只能与同区通信。
  4. if len(peers) < self.majority:CP 写入的核心检查:可达副本不足多数派就拒绝写入。
  5. for n in peers: n.write(value)CP 要求多数派内所有副本都更新后才返回成功。
  6. store.write_ap(store.nodes[2], 3)AP 模式下分区内的节点直接本地写入,不等待多数派。
  7. print("divided state:", store.read_all())展示分区期间两侧各自的值(2 和 3),不一致窗口出现。
  8. store.set_partition({"A": 1, "B": 1, "C": 1})恢复网络(分区消除),为最终收敛做准备。

常见误区

误区很多教程说 Cassandra 是最终一致的,所以它不满足 CAP 的 C;那 CAP 的 C 是不是就是“数据最终会对齐”?

正解CAP 的 C 特指线性一致性(linearizability),即读操作必须反映“某个逻辑时刻之后”最新的写结果。最终一致性是 AP 系统在分区结束后收敛的性质,讨论的是“分区结束后数据如何趋同”,两者根本不是同一个概念。一个系统完全可以在正常情况下提供强一致,在分区时降级为最终一致,不能简单用“最终一致”概括它的 C。

为何常见:最终一致性这个词传播最广,新手容易把“数据最终会一样”理解成“一致性”,忽略了 CAP 对一致性的严格定义。

误区CAP 既然是三选二,那我可以选 CA——只要网络足够稳定,没必要管分区容错,把精力都放在强一致和高可用上。

正解P 不是“功能开关”而是“环境事实”。只要系统节点分布在不同机器、不同机房,网络分区、丢包、时钟漂移就必然存在概率。CAP 的真正表述是:当分区发生时,C 和 A 只能保一个;无分区时两者可以同时满足。CA 系统只在理想的“无分区”假设下成立,在真实分布式环境里不存在。

为何常见:“三选二”这个口头禅太顺口,容易让人以为三个是平等的可选项,而忽略了 P 是分布式系统的默认前提。

误区选了 CP,系统在分区时整个服务停摆;选了 AP,系统数据永远对不上,业务没法做。

正解CP 系统分区时只是“无法保证所有副本一致的那部分写入”被拒绝,多数派一侧通常仍可正常服务;AP 系统通过版本号、时间戳、CRDT 等机制在恢复后自动收敛。两者都有大量生产实践支撑,差别是权衡窗口和恢复机制,不是“好与坏”的差别。

为何常见:把生活中的“要么全对要么全错”二元思维带进来,忽略了 CAP 讨论的是“分区期间”这个特定时间窗,而不是系统的常态表现。

误区既然 CAP 这么重要,那我可以给整个系统定一个 CP 或 AP 的策略,一劳永逸。

正解生产系统是分层混合的:订单、库存这类核心写路径选 CP;阅读数、点赞、推荐这类读多写少、可容忍延迟的走 AP。同一套架构里既有强一致的 MySQL 主从和 etcd,也有最终一致的缓存和消息队列。架构师按数据重要性和业务容忍度逐条决策,而不是给整个系统贴一个标签。

为何常见:CAP 以“系统”为单位讨论,容易让人忽略系统内部可以按数据、按接口、按故障域做细粒度拆分。

误区机房光纤很稳,一年也遇不到一次分区,主要精力应该放在性能优化上,不用为小概率事件做预案。

正解在分布式系统里,交换机升级、云厂商故障、GC 停顿造成的心跳超时都可能触发“逻辑分区”。除非系统只有单副本,否则设计必须假设分区会来,并提前定好降级预案。预案平时不触发,但一旦触发,就决定用户感知到的是一致性问题还是可用性问题。

为何常见:单点、小规模系统很少遇到分区,经验局限让人低估了分区的发生概率——它往往不是“线路断了”,而是各种隐性原因导致的“消息不通”。

面试题

Q1. CAP 定理中的"P"(分区容错)本质是指什么?

单选题 · easy

  • A.系统能容忍部分节点宕机
  • B.网络消息丢失或节点失联← 正确答案
  • C.数据可以在机房间迁移备份
  • D.系统能自动恢复被删除的数据

答案:B。P 指网络分区,即节点间的消息会丢失、延迟或无法到达。宕机只是可能触发分区的一种原因,迁移备份、数据恢复都不是 P 的定义。就像奶茶店电话线断了,核心问题是“消息传不过去”。

Q2. 关于“三选二”的正确理解是?

单选题 · easy

  • A.三个属性可以任选两种来设计
  • B.分区时 C 和 A 只能保全一个← 正确答案
  • C.无分区时也必须放弃一种
  • D.分区容错在实际中总能避免

答案:B。CAP 定理说分布式系统中 P 是必须面对的现实,分区发生时 C 与 A 不可兼得;无分区时两者可同时满足。“三选二”是简化说法,不是自由任选——你不能选"CA"然后指望网络永远不断。

Q3. ZooKeeper 在发生网络分区时的行为属于?

单选题 · mid

  • A.保证可用性牺牲部分一致性
  • B.保证一致性拒绝非多数派请求← 正确答案
  • C.同时保持强一致和高可用访问
  • D.自动切换到灾备机房继续服务

答案:B。ZooKeeper 是典型 CP 系统:分区后少数派节点不再接受读写,多数派集群继续服务,保证线性一致性。它宁可让少数派“暂停营业”,也不让顾客看到错误价格。

Q4. AP 系统的数据“最终一致”通常依赖什么实现?

单选题 · mid

  • A.事务提交后全局加分布式锁
  • B.版本号与冲突合并机制来收敛← 正确答案
  • C.所有写入必须获得多数派确认
  • D.客户端本地缓存全部数据副本

答案:B。AP 系统不强求多数派确认,用版本号、时间戳、CRDT 等在恢复后合并冲突、收敛一致。A 和 C 是 CP 的典型手段;D 与 AP 无关。就像奶茶店恢复电话后靠账本对账,而不是断线时锁死柜台。

Q5. 以下属于 CP 策略的机制有?

多选题 · mid

  • A.写入需多数派副本确认← 正确答案
  • B.分区时少数派拒绝服务← 正确答案
  • C.冲突双方各自保留旧版本
  • D.心跳选举产生唯一主节点← 正确答案

答案:ABD。A、B、D 是 CP 的典型机制:多数派确认、拒绝降级、选主。C 是 AP 策略——保留冲突版本等待合并。CP 的目标是“宁可等,也不给错价”。

Q6. 下列哪个系统通常被认为采用 AP 策略?

单选题 · easy

  • A.ZooKeeper 使用 ZAB 协议选主
  • B.MySQL 主从同步保证强一致性
  • C.DynamoDB 默认多区域最终一致← 正确答案
  • D.etcd 写入需 Raft 多数派确认

答案:C。ZooKeeper、MySQL 同步复制、etcd 都是 CP 系或强一致配置;DynamoDB 默认多活、允许最终一致,是典型 AP。AP 系统追求“先营业后对账”。

Q7. 生产系统常进行 CP/AP 混合设计,合理做法有?

多选题 · hard

  • A.订单扣库存走强一致的 CP 链路← 正确答案
  • B.点赞计数走异步最终一致更新← 正确答案
  • C.所有读写必须由单一中心节点处理
  • D.核心链路降级时启动缓存兜底← 正确答案

答案:ABD。混合设计按数据重要性分流:核心强一致、边缘最终一致、故障降级兜底。C 把所有流量集中到单一中心节点,与分布式设计的初衷相悖,也不属于混合策略。

Q8. 下列关于 PACELC 扩展模型的描述,正确的是?

单选题 · hard

  • A.分区时只考虑可用性这一个指标
  • B.无分区时权衡延迟和一致性即可← 正确答案
  • C.该模型完全取代了 CAP 定理本身
  • D.平时权衡点位于可用性和分区容错

答案:B。PACELC 补充了 CAP 没覆盖的“无分区”场景:分区时(P)选 A 或 C,否则(Else)在延迟(L)与一致性(C)间权衡。它是 CAP 的扩展而非取代,平时权衡的是延迟和一致性,不是可用性和分区容错。

Q9. 网络分区发生时,AP 系统可能出现的现象有?

多选题 · mid

  • A.两侧同时写入互相冲突的数据← 正确答案
  • B.读到尚未同步的过期旧数据← 正确答案
  • C.分区结束后执行冲突合并收敛← 正确答案
  • D.少数派副本拒绝处理任何读取

答案:ABC。AP 允许两侧继续服务,代价是短暂不一致、冲突和读到旧数据,恢复后收敛。D 是 CP 行为——拒绝少数派读取。AP 对应的是“先营业,后对账”。

Q10. CAP 定理的证明中,核心矛盾发生在什么场景?

单选题 · extreme

  • A.节点宕机后从备份中恢复数据
  • B.分区时两侧同时响应同一次请求← 正确答案
  • C.请求在正常网络中被延迟处理时
  • D.客户端并发发起大量重复的请求

答案:B。证明把系统分成两组,假设中间网络断开。若两侧都能及时响应同一个写请求,则任一侧可能读到旧值,破坏一致性;若必须等对方确认,等待时间无限,破坏可用性。正是“同时响应”这个要求让 C 和 A 不可兼得。