想象一下,你们一家四口人分散在四个城市生活,却共同使用同一本家庭账本。爸爸在北京记了一笔“买了年货 500 元”,妈妈在上海写的是“水电费 300 元”,哥哥在深圳添了一行“聚餐 80 元”,姐姐在杭州刚记下“打车 25 元”。每个人手里的账本都是自己随手写的副本,当大家月底视频对账时,问题来了——谁手头的账本才是“最新最全”的?怎么保证四个城市的人看到的账本内容都一样?倘若某一刻电话线路还中断了(网络分区),大家又该怎么继续记账? 这正是分布式系统中“一致性保证”要解决的核心难题。现实世界里的服务器集群、数据库多副本,就像分散在四地的家庭成员,每一个节点都握着数据的“副本账本”。本文会用这个贯穿始终的比喻,带你从一致性基础、CAP 定理、一致性协议、共识算法,一路聊到工程实践、分布式事务和面试应对技巧。你会发现,那些看似复杂的分布式理论,本质上就是在回答“怎么让一家人对同一本账本永远不吵架”。

岗位关联

对 AI 从业者而言,一致性保证是系统设计的灵魂问题。无论你做推荐系统、大模型推理服务还是 AI 中间件,数据多副本、分布式协调、事务处理都绕不开这套思维模型,面试中它更是架构设计题的必考点。

目录
  1. 可视化演示
  2. 一致性基础
  3. CAP定理解读
  4. 一致性协议
  5. 共识算法
  6. 工程实践
  7. 分布式事务
  8. 面试应对
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示分布式系统一致性保证的核心机制,包含CAP定理权衡、Raft共识算法日志复制流程与强一致性/最终一致性模型时序对比。

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

CAP定理:分区时的权衡 一致性:所有节点同一时刻看到相同数据 可用性:系统始终可响应请求 CAP = C + A + P (pick 2) 网络分区时只能选择CP或AP,无法同时保证

一致性基础

一家人分散四地,爸爸在北京、妈妈在上海、哥哥在深圳、姐姐在杭州,各自手里攥着一本“家庭账本”。今天爸爸花了 500 元,明天妈妈又花 300 元,如果大家不及时把新账目抄送给彼此,月底对账时就会吵翻天。一致性要回答的正是这个问题:当数据有多个副本时,如何让所有副本读到的值保持一致。

在计算机世界里,那些分散在各地的家庭成员就是一个个数据节点,手里的账本副本就是数据副本。强一致性意味着:任何一个节点写入新数据后,所有其他节点立刻就能读到这个新值,就像爸爸刚写完“500 元”,妈妈下一秒翻账本也能看到一样。弱一致性则允许短暂“看不见”,最终一致性是最实用的弱一致模型——只要等待一段时间(如网络传播完成),所有副本最终会收敛到相同的值。

所以一致性级别就像家庭的“账本管理规矩”:有的家庭要求任何成员随时翻账本都必须一模一样(强一致);有的家庭允许你先用自己手里的旧账本,晚上大家再统一更新(最终一致)。理解这一点,后面讨论 CAP 定理时才能有根基。

∀r1,r2∈R,V(r1,t)=V(r2,t)\forall r_1, r_2 \in \mathcal{R},\quad V(r_1, t) = V(r_2, t)
这个公式表示:对副本集合 R 中的任意两个副本 r₁ 和 r₂,在时刻 t 读取到的值 V 必须完全相等。这是强一致性的数学刻画。
  1. 副本集合与取值函数集合 R 包含系统中的所有副本节点,函数 V(r, t) 表示在时刻 t 读取副本 r 得到的值。
    R={r1,r2,…,rn},V(r,t)=节点r在时刻t的值\mathcal{R}=\{r_1, r_2, \ldots, r_n\},\quad V(r,t)=\text{节点r在时刻t的值}
  2. 任意(∀)量词符号 ∀ 表示“对每一个”,意味着必须检查所有副本,而不只是其中几个“听话的”。
    ∀r1,r2∈R\forall r_1, r_2 \in \mathcal{R}
  3. 等值约束右边要求两个副本在同一个时刻 t 的值相等,任何一秒的偏差都不被允许。
    V(r1,t)=V(r2,t)V(r_1, t) = V(r_2, t)

CAP定理解读

某天,连接四座城市的电话线全部断了。爸爸刚记了 500 元年货支出,妈妈也刚记了 300 元水电费,两边都不知道对方的新账目。此时如果想保证“大家账本完全一致”,就只能让大家先暂停记账,等线路恢复再说——这牺牲了可用性;如果想让大家都继续正常记自己的账,就必须容忍账本暂时不一致。

这就是 CAP 定理的精髓:在分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者无法同时满足。特别要注意的是,分区(P)不是你可以选择的选项——网络故障是常态,所以系统只能在 C 和 A 之间做取舍。这就好比电话线已经断了,你没法选择“线路不断”,只能选择“是让大家停笔等同步,还是各记各的账”。

实际工程中,ZooKeeper 选择优先保证一致性(CP),牺牲了一部分可用性;而 Eureka 注册中心选择优先保证可用性(AP),允许节点间暂时读到不一致的数据。回到家庭比喻,CP 家庭选择“打不通电话就暂停记账”,AP 家庭选择“先各记各的,等线路通了再合并”。没有绝对的对错,只有适不适合场景。

P=1  ⇒  C+A≤1P=1 \;\Rightarrow\; C+A \le 1
当分区发生时(P=1),一致性收益 C 与可用性收益 A 之和最多为 1,二者必须二选一。
  1. 三字母标记C、A、P 在公式中取 0 或 1,1 表示“必须得到保证”,0 表示“可以暂时放弃”。
    C,A,P∈{0,1}C, A, P \in \{0, 1\}
  2. 分区为前提P=1 表示网络分区已经真实发生,这个约束是客观的,不是你可以调优的选项。
    P=1P=1
  3. 取舍上限当 P=1 时,C+A 的值不可能大于 1,说明你无法同时获得一致性和可用性。
    C+A≤1C + A \le 1

一致性协议

一家人打算买一台昂贵的按摩椅,金额很大,必须全家统一意见才能下单。于是爸爸作为“协调者”挨个给妈妈、哥哥、姐姐打电话:第一阶段问“你同意买吗”,每个人回答同意或反对;第二阶段,只有当所有人都同意时才下单付款。如果有一人反对,就取消购买。这就是两阶段提交(2PC)的运作方式。

2PC 将一次分布式事务拆成 Prepare(预备)和 Commit(提交)两个阶段,由协调者统一发起,所有参与者必须全部投“同意票”才能提交。它的优点是逻辑简单清晰,缺点是阻塞——如果协调者在第二阶段宕机,所有参与者只能一直等待,就像爸爸电话打到一半突然没电,全家人只能握着电话干等。

由于 2PC 的阻塞缺点,又出现了三阶段提交(3PC),引入超时机制来避免长时间阻塞;再往后,工程界广泛使用柔性事务,不再要求强一致,而是通过补偿让系统最终达到一致。就像家庭购物,有时不必等所有人接电话,只要多数人同意先买,事后跟没接到电话的人说一声也算数。

Commit  ⟺  ∀p∈P, vote(p)=YES\text{Commit} \iff \forall p\in \mathcal{P},\ \text{vote}(p)=\text{YES}
提交事务当且仅当参与事务的每一个节点 p 在准备阶段都投出 YES 票。
  1. 参与者集合集合 P 是参与这次事务的所有数据节点,对应家庭中的每位成员。
    P={p1,p2,…,pn}\mathcal{P}=\{p_1, p_2, \ldots, p_n\}
  2. 投票函数vote(p) 返回节点 p 在 Prepare 阶段的决定,是一个赞同或反对的二元结果。
    vote(p)∈{YES,NO}\text{vote}(p) \in \{\text{YES}, \text{NO}\}
  3. 双向等值符号⟺ 表示“当且仅当”——提交事务与“所有人赞成”互为充要条件,少一票都不行。
    Commit  ⟺  ∀p, vote(p)=YES\text{Commit} \iff \forall p,\ \text{vote}(p)=\text{YES}

共识算法

在分布式系统中,比“提交一笔事务”更基础的问题是:多个节点如何就某个值达成一致?比如家庭要选出一个“记账负责人”,以后所有开销都由他汇总,那么四家人各执一词,听谁的?最简单的办法是少数服从多数——只要有超过半数的家庭成员同意某个人,就选他当负责人,其余人跟随。

共识算法就是为解决这类问题而诞生的数学协议。Paxos 是学术界第一个被证明正确的共识算法,但实现起来极其晦涩;Raft 在 Paxos 基础上做了工程化简化,将问题拆解为领导者选举(Leader Election)、日志复制(Log Replication)和安全性三大模块,因此被 ZooKeeper 之外的众多系统(如 etcd)采用。

回到家庭比喻,只要超过两个人认可“爸爸当记账负责人”,那么以后所有账目都由爸爸统一登记,再抄送给其他人。如果爸爸暂时失联(宕机),大家就重新投票选一个新的负责人。Raft 正是用这种“过半投票 + 日志同步”机制,在节点可能故障的现实中仍然保证数据的一致。

Q>n2Q > \frac{n}{2}
达成共识需要获得超过半数的节点票数,其中 n 是节点总数,Q 为获得票数的节点数量。
  1. 节点总数n 表示参与共识过程的全部节点个数,对应家庭成员的个数。
    n=∣P∣n = |\mathcal{P}|
  2. 法定票数集合Q 表示实际投赞成票的节点数量,它是一个计数结果。
    Q=赞成票数=∑p∈P1赞成(p)Q = \text{赞成票数} = \sum_{p \in \mathcal{P}} \mathbb{1}_{\text{赞成}}(p)
  3. 严格过半只有 Q 严格大于 n 的一半,决策才被采纳,这是避免平局和双主的关键。
    Q>n2Q > \frac{n}{2}

工程实践

账本到底怎么抄写和同步?最常见的是主从复制:爸爸是主节点,拥有唯一的写权限;哥哥姐姐都是从节点,只能读爸爸抄送过来的内容。这种模式实现简单,但主节点故障时可能丢失最新账目,所以实践中还要配合多主复制或无主复制来提升可用性。

当系统允许从多个节点读写时,就需要一个仲裁规则保证“读到的数据足够新鲜”。这个规则叫 Quorum 机制:一次写操作必须成功写入至少 W 个节点,一次读操作必须至少读取 R 个节点,只要满足 W+R>N(N 为副本总数),读写的节点集合必定有交集,从而保证能读到最新写入的数据。

除此之外,工程中还常用版本向量来检测并发写冲突——好比每个家庭成员给账本加一个“版本号”,谁改动过就留下标记,合并账本时发现两个不同版本就知道冲突了。这些都是保证“家庭账本”在多节点间最终一致的重要工具。

W+R>NW + R > N
写操作的节点数 W 与读操作的节点数 R 之和大于副本总数 N 时,任意一次读操作都能遇到至少一个已经包含最新写入的节点。
  1. 三个参数定义N 为副本总数,W 为每次写入必须确认的副本数,R 为每次读取必须查询的副本数。
    N>0,1≤W≤N,1≤R≤NN>0,\quad 1 \le W \le N,\quad 1 \le R \le N
  2. 集合必然相交把 W 个成功写节点看成一个集合,R 个读取节点看成另一个集合,当两者元素个数之和超过 N 时,两个集合不可能不相交。
    写集合∩读集合≠∅\text{写集合} \cap \text{读集合} \neq \emptyset
  3. 工程含义由于两个集合有交集,读操作必然看到写入的最新值,从概率上消除了“脏读”的可能。
    P(读到最新值)=1P(\text{读到最新值}) = 1

分布式事务

家里计划一次集体旅行,需要依次预订机票、酒店、门票和接驳车。这四步分布在不同的平台上(比如不同微服务)。如果机票订好了、酒店也订好了,但门票预订失败,前面订好的机票和酒店怎么办?这就是分布式事务要解决的问题:一次业务操作横跨多个服务,不可能用单个数据库本地事务一把锁住。

业界常用的方案包括:本地消息表(本地事务写一条消息,异步告知下游)、TCC 模式(Try-Confirm-Cancel,三个动作分别预留资源、确认、取消)、SAGA 模式(正向执行各个子事务,某一步失败后反向补偿),以及可靠消息队列(通过消息中间件异步保证最终一致)。SAGA 在微服务中尤为流行:每个子事务都有对应的补偿事务,一旦流程中断就逐步撤销已经完成的操作。

这好比旅途计划到“订门票”时发现没票了,那就赶紧把机票退掉、酒店取消——虽然经历了反向操作,但最终全家回到“没花钱”的一致状态。分布式事务的哲学正是:不追求每一步同时成功,而是最终大家都能回到一致的状态。

Tk 失败  ⇒  Ck−1→Ck−2→⋯→C1T_k\ \text{失败}\;\Rightarrow\; C_{k-1} \to C_{k-2} \to \cdots \to C_1
当正向事务的第 k 步 T_k 失败时,系统会从第 k-1 步开始,依次执行补偿操作 C,把前面各步骤带来的影响撤销掉。
  1. 正向序列T₁ 到 Tₙ 是按顺序执行的业务步骤,比如订机票、订酒店、买门票。
    T1→T2→⋯→TnT_1 \to T_2 \to \cdots \to T_n
  2. 补偿操作C_i 是步骤 T_i 的补偿(撤销)操作,对应退票、退房、退款。
    Ci=undo(Ti)C_i = \text{undo}(T_i)
  3. 失败触发回退如果 T_k 执行失败,就执行比 k 小的所有补偿操作,直到恢复初始状态。
    Tk 失败  ⇒  Ck−1,Ck−2,…,C1T_k\ \text{失败} \;\Rightarrow\; C_{k-1}, C_{k-2}, \ldots, C_1

面试应对

当面试官问“如何设计一个保证一致性的系统”时,很多人的第一反应是背 CAP 定理。这有点像家里对账时,只喊“我们要一致!”却说不清到底哪种一致、允许多久不一致。面试官真正想看的是你面对场景权衡利弊的能力。

一个实用的答题框架是四步走:第一,明确一致性需求——这个业务允许最终一致吗?还是必须强一致?第二,评估可用性目标——系统宕机时间上限是多少?第三,选择技术方案——强一致选 ZooKeeper / etcd 这类 CP 系统,高可用选 AP 系统,事务场景选 SAGA 或 TCC。第四,说明权衡与演进——为什么选它,牺牲了什么,未来数据量增长后如何扩展。这个框架就像请财务顾问给家庭记账:先问家里一个月花多少,再决定用哪本账、怎么对账。

面试中抛出这个公式,能展示你对“副本数量、一致性代价、可用性收益”三者关系的量化理解。回到比喻,如果家里只有一本账本,这本账丢了全家就完蛋;如果抄了四本分别放在四个城市,一本被烧了还能靠另外三本恢复——但代价是要花心思保证四本账内容一致。这就是“多副本 → 可用性上升,但一致性成本也会上升”的本质。

Atotal=1−(1−Anode)NA_{\text{total}} = 1 - (1 - A_{\text{node}})^N
这是一个经典的可用性估算公式:单节点可用率为 A_node,当部署 N 个副本时,整个系统的可用率 A_total 会显著提升。
  1. 单点可用率A_node 表示单个节点在一年中正常运行时间的比例,比如 0.99 代表 99% 可用。
    Anode∈[0,1]A_{\text{node}} \in [0,1]
  2. 整片宕机概率系统不可用要求所有 N 个副本同时故障,其概率是每个节点不可用率的 N 次方。
    (1−Anode)N(1 - A_{\text{node}})^N
  3. 用 1 减去用“1 - 全部故障概率”得到系统整体的可用率,副本越多,可用性越高。
    Atotal=1−(1−Anode)NA_{\text{total}} = 1 - (1 - A_{\text{node}})^N

AI 应用场景

分布式注册中心选型

阶段:系统架构设计阶段

解决的问题:AI 微服务集群通常有几十上百个服务实例,它们需要互相发现并维系心跳。传统单机注册表无法支撑高并发状态同步,若注册中心本身崩溃,整个 AI 平台将像失去电话簿的家族,谁也找不到谁。

具体案例:某 AI 平台有 50 个模型推理服务实例,使用 Eureka 做注册中心。Eureka 优先保证可用性(AP),允许实例间注册信息短暂不一致,服务间偶尔出现调用失败由客户端重试兜底;若改为 ZooKeeper,则能保证注册数据强一致(CP),但在网络抖动时可能短暂拒绝服务。选型时需结合 AI 服务对可用性的敏感度决定。

订单与库存系统的事务补偿

阶段:业务服务开发与数据一致性维护阶段

解决的问题:AI 电商平台中,下单、扣库存、积分变动分属不同服务。传统本地事务无法跨服务回滚,容易出现“订单成功但库存超卖”的严重事故。

具体案例:某电商平台在订单流程中引入 SAGA 模式,正向执行创建订单 → 扣减库存 → 增加积分;若扣库存失败,则触发取消订单的补偿事务。配合本地消息表,使最终一致率达到 99.99% 以上,秒杀高峰也不再超卖。

分布式锁与选主机制

阶段:分布式任务调度阶段

解决的问题:AI 训练任务需要保证同一时间只有一个 worker 在写模型 checkpoint,否则多个节点同时写会造成模型版本混乱,如同全家四个人同时往同一本账上乱写一样。

具体案例:某模型训练平台使用 etcd(基于 Raft 共识)实现分布式锁,节点通过 etcd 选主,只有 leader 节点能写入 checkpoint。当 leader 宕机,剩余节点重新选主,整个过程对上层透明,模型参数不再出现版本冲突。

Python 演示

python35 行
import random  def run_trial(n, w, r):    nodes = [0] * n    written = set()    while len(written) < w:        idx = random.randrange(n)        nodes[idx] = 1        written.add(idx)    read_set = set()    while len(read_set) < r:        read_set.add(random.randrange(n))    return any(nodes[i] == 1 for i in read_set)  def stale_rate(n, w, r, trials=2000):    stale = 0    for _ in range(trials):        if not run_trial(n, w, r):            stale += 1    return stale / trials  def main():    n = 5    configs = [(2, 2), (3, 3), (4, 3)]    for w, r in configs:        s = stale_rate(n, w, r)        cond = "成立" if w + r > n else "不成立"        print("N=%d W=%d R=%d quorum条件%s 陈读率=%.3f" % (n, w, r, cond, s))  if __name__ == "__main__":    main()
目的:通过随机模拟验证 Quorum 机制的核心结论——当 W+R>N 时读操作必然读到最新写入,陈旧读率为 0;当 W+R≤N 时陈旧读率显著上升。
  1. written = set()用一个集合保证一次写入确实落在 W 个不同节点上,避免重复写同一节点导致仲裁失效
  2. while len(written) < w循环直到选中 W 个不同节点,对应 Quorum 写入的“至少成功写 W 个副本”要求
  3. read_set = set()读取操作同样需要挑出 R 个不重复节点,模拟客户端同时查询多个副本
  4. any(nodes[i] == 1 for i in read_set)只要读的节点中出现最新值,就判定本次读取成功
  5. stale_rate用 2000 次蒙特卡洛模拟统计陈旧读概率,让抽象定理变成可观测的数字
  6. configs = [(2, 2), (3, 3), (4, 3)]三组参数分别对应 W+R≤N、W+R>N、W+R>N 的情况,便于对比
  7. if __name__ == "__main__":标准入口,保证脚本可以直接运行也可被导入为模块

常见误区

误区很多人以为 CAP 定理是说一致性、可用性、分区容错性三个特性里,系统设计时随便挑两个满足就行,甚至可以主动放弃分区容错性来保证其他两者。

正解分区容错性(P)是分布式系统的客观前提,不是可选项——网络一定会出故障,服务器一定会宕机。CAP 真正的含义是:当分区已经发生时,你只能在 C 和 A 之间做选择。没有分区的时候,C 和 A 完全可以同时满足。就像家庭电话线已经断了,你只能决定“停笔等同步”还是“各自先记账”,不能假装电话没断。

为何常见:因为 CAP 的经典表述“三者不可兼得”过度简化,很多教材把 P 描述成与 C、A 并列的可选特性,导致读者误以为三者可以随意取舍。

误区面试者常认为 2PC 既然能让所有节点统一提交,就应该是分布式事务的标准解法,高并发场景直接套用即可。

正解2PC 存在严重的阻塞问题:协调者宕机时,参与者会一直持有资源等待,系统吞吐骤降;协调者单点故障甚至可能让事务永久悬置。因此现代分布式系统更倾向于使用 SAGA、TCC 等柔性事务方案,用最终一致性换取可用性。

为何常见:因为 2PC 是最先被系统化讲授的分布式事务协议,概念上容易理解,初学者很容易把它当成万能模板。

误区很多人听到“最终一致”就认为系统允许永久出现脏数据,把最终一致和有数据错误画等号。

正解最终一致性是指副本数据会在有限时间内收敛到一致状态,只是“延迟一致”。例如 DNS 解析在全球的传播就是最终一致,几小时内所有节点都会看到同一份记录。它可以被量化:系统规定了最大收敛时间。对应家庭账本,就是“月底前大家务必完成对账”,不是“永远不用对账”。

为何常见:因为“弱一致”这个上位概念里包含“读取可能拿到旧值”的现象,学习者把旧值误解为错误值,忽略了它最终会修复的特性。

误区以为只要配置了满足 W+R>N 的读写参数,系统就一定不会出现任何读到旧值的情况。

正解W+R>N 保证的是读集合与写集合有交集,但如果节点包含旧版本数据却无人修复,读到的仍可能是旧值。实践时还需要配合版本号比较、读修复(Read Repair)或冲突合并策略,才能真正保证读取到最新数据。就像四本账本里有一本漏记了账单,你即使读到这本能从中发现“版本号更旧”,还要让它去抄新账本才行。

为何常见:因为公式本身非常简洁优美,学习者容易只记住结论,忽略现实中节点落后、网络重试、并发写等复杂情况。

面试题

Q1. 根据 CAP 定理,当网络分区(P=1)已经发生时,系统必须做出的选择是__

单选题 · easy

  • A.同时放弃一致性和可用性
  • B.在一致性和可用性之间二选一← 正确答案
  • C.同时保证一致性和可用性
  • D.放弃分区容错性来换取一致

答案:B。CAP 要求在分区发生时,C 与 A 必然冲突,只能二选一。选项 A 不是选择,C 违背定理,D 因 P 是客观不可放弃而错误。可用家庭断线后“停笔同步”或“各自记账”来理解。

Q2. 强一致性最准确的含义是__

单选题 · easy

  • A.所有副本在任意时刻读到的值相同← 正确答案
  • B.副本值最终会趋同但时间不确定
  • C.只要主节点数据正确即可
  • D.数据允许永久处于不一致状态

答案:A。强一致性要求任意时刻所有副本读值相同(对应公式 ∀r, V(r,t) 相等)。B 描述的是最终一致性,C 忽略副本同步,D 与一致性概念相反。

Q3. 两阶段提交中,第二阶段执行的动作是__

单选题 · easy

  • A.Prepare 预备资源阶段
  • B.Commit 正式提交阶段← 正确答案
  • C.Vote 征集意见阶段
  • D.Ping 网络探测阶段

答案:B。2PC 第一阶段 Prepare 征集投票,第二阶段根据投票结果执行 Commit 或 Abort。A 和 C 都是第一阶段内容,D 不属于 2PC 阶段。

Q4. Raft 算法中,领导者选举获胜需要获得__

单选题 · mid

  • A.必须获得全体节点的同意票
  • B.严格超过半数的节点选票← 正确答案
  • C.超过三分之二节点的选票
  • D.至少百分之八十节点选票

答案:B。Raft 使用过半投票(Q>n/2)即可选出唯一 Leader,不必全体同意,也不需三分之二或 80% 多数。这与家庭选记账负责人只需多数票同意一致。

Q5. Quorum 机制中,为了确保读取时能看到最新写入,必须满足的条件是__

单选题 · mid

  • A.写入副本数 W 必须等于 N
  • B.读取副本数 R 必须等于 1
  • C.写入数 W 与读取数 R 之和大于 N← 正确答案
  • D.写入数 W 与读取数 R 之和小于 N

答案:C。W+R>N 保证写节点集合与读节点集合必然有交集,因此读到最新值概率为 1。A 过于严格不必要,B 无法保证交集,D 恰恰会导致读不到最新数据。

Q6. 以下属于柔性分布式事务方案的有__

多选题 · mid

  • A.本地消息表,通过本地事务写消息异步通知← 正确答案
  • B.TCC 模式,先 Try 预留资源再 Confirm 确认← 正确答案
  • C.SAGA 模式,失败时执行反向补偿事务← 正确答案
  • D.单机数据库使用事务锁协调多个操作

答案:ABC。本地消息表、TCC、SAGA 都允许跨服务最终一致,属于柔性事务。D 是单机本地事务,只能保证单数据库内的 ACID,无法解决跨服务问题。

Q7. ZooKeeper 在 CAP 偏向上通常被认为是__

单选题 · mid

  • A.优先保证一致性,属于 CP 系统← 正确答案
  • B.优先保证可用性,属于 AP 系统
  • C.完全无法保证任何一致性
  • D.不用保证分区容错性即可运行

答案:A。ZooKeeper 在遇到分区时宁可拒绝服务也要保证数据一致,因此是 CP 系统代表。B 描述的是 Eureka、Cassandra 的选择,C 与事实相反,D 忽略了分区的必然性。

Q8. Raft 共识算法包含的核心机制有__

多选题 · hard

  • A.Leader 选举,选出唯一的领导节点← 正确答案
  • B.日志复制,把操作同步到所有节点← 正确答案
  • C.配置变更,安全调整集群成员← 正确答案
  • D.全局时钟,给每个操作加时间戳

答案:ABC。Raft 由 Leader 选举、日志复制、安全性、配置变更等机制组成。全局时钟不是 Raft 的组成机制,Raft 依靠任期号和日志比较而非物理时钟。

Q9. 系统可用性公式 A=1-(1-a)^N(a 为单节点可用率)说明__

单选题 · hard

  • A.副本越多时单点故障概率反而越高
  • B.多副本部署能显著提升整体可用性← 正确答案
  • C.副本数量对可用性完全没有影响
  • D.只要副本多就必然能做到强一致

答案:B。多副本同时故障的概率为 (1-a)^N,随 N 增大快速下降,因此整体可用性上升。A 违背概率常识,C 否定了公式,D 混淆了可用性与一致性两个维度。

Q10. 关于 Paxos 与 Raft 的关系,正确的说法是__

单选题 · extreme

  • A.Raft 与 Paxos 在理论上完全无关
  • B.Raft 简化 Paxos 且比后者更易工程实现← 正确答案
  • C.Paxos 已被 Raft 彻底替代而无研究价值
  • D.两者都要求所有节点必须同时在线

答案:B。Raft 的日志同步思路源于 Paxos,但通过 Leader 选举和日志顺序极大降低了理解成本,因此更易落地。A 忽视了继承关系,C 过度绝对,D 错误——共识算法正是为了容忍节点故障而设计。