假设你是某五星级大酒店的“总管家”,今晚要办一场 800 人的婚宴。凉菜、热菜、甜品三个厨房各管一摊,任何一道菜晚 30 秒上桌,整场宴席都会乱套。你会怎么做?最稳妥的办法,是开席前先给每个厨房打电话:“能按时出菜吗?”厨房们把食材备好、锅烧热、装盘待命,但先不动勺;三家都回“能”,你才下令“上菜!”;只要有一家说“不行”,你立刻喊“撤!”。这套“先问一圈、再统一行动”的协调思路,正是分布式系统里最经典的原子性保障——两阶段提交(Two-Phase Commit,2PC)的雏形。 本文就用这场婚宴当主线,带你搞懂 2PC 的协调流程、超时处理、故障恢复,以及它为什么有“端盘干等”的毛病,又该如何改进。你会发现,婚宴总管家和分布式协调者面对的问题惊人地一致:既要让多个独立单元同步行动,又要防备有人临时掉链子。
学完本节,你将能用“总管家统筹婚宴”的直觉把握 2PC 的协调流程与故障边界,在面试和架构选型中准确说出它的适用场景与改进方向,明白为什么“先问一圈”能换来原子性,也清楚它要付出什么代价。
目录
可视化演示
展示2PC三模式:Prepare-Commit两阶段消息流(协调者CRD与P0-P2参与者双向通信+四阶段时间线)、故障恢复(协调者/参与者/网络/超时四场景+日志重放检查点心跳备用协调四策略+超时阈值)、2PC vs 3PC对比(阻塞vs非阻塞+消息数延迟可用性三维性能对比)。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Prepare-Commit两阶段消息流 CRD协调者向P0/P1/P2发送Prepare,参与者投票Yes/No 全部Yes则Commit,任一No则Abort,保证原子性 2PC = Prepare(vote) + Commit/Abort 延迟50ms,12条消息,成功率97%
协调者角色:婚宴的总管家
婚宴不能每家厨房自己决定几点上菜——凉菜觉得 6 点好,热菜非要 7 点,甜品拖到 8 点,宾客早掀桌了。所以酒店会指定一个总管家来统一指挥:他决定开席时间、给厨房派活、收拢反馈、最终拍板。在 2PC 里,这个角色叫协调者(Coordinator),所有参与事务的节点叫参与者(Participant),协调者只有一个,是全局唯一的“拍板人”。
协调者不是打杂跑腿,它的职责有四项:事务发起——收到业务请求后创建本次全局事务;唯一决策——只有它能决定提交还是中止;消息收发——向所有参与者广播询问、收集投票、分发决策;状态维护——记录当前处于准备阶段还是提交阶段。你可以把它理解成总管家手里那份“开席流程表”,所有事情都以这张表为中心推进。
从集合论的角度看,协调者与参与者把系统节点划分成了两个互不重叠的角色:
理解了角色分工,你会明白 2PC 的全部秩序都系于协调者一身。这个设定带来简洁,也为后文的“阻塞问题”埋下伏笔——总管家权力越集中,他一旦倒下,影响就越大。
- 全量节点集合\mathcal{N} 表示分布式系统中全部节点的集合,就像婚宴里所有参与出菜的厨房。
- 角色零交叉\mathcal{C} 是协调者节点,\mathcal{P} 是参与者节点,二者交集为空,同一节点不会同时又当裁判又当运动员。
- 唯一决策者|\mathcal{C}| = 1 保证系统里只有一个“总管家”,避免两个管家喊出互相矛盾的口令。
准备阶段:先备菜,先别动勺
总管家开席前的第一通电话,就是“预询”。他不会直接喊“上菜”,而是先问:“凉菜,6 点能出吗?热菜,能吗?甜品,能吗?”每个厨房收到询问后,把食材切好、锅烧热、盘子摆齐——一切都准备好,但菜先不上桌,因为万一有人不行,撤起来太狼狈。这个“备好但不生效”的动作,对应 2PC 的第一阶段:准备阶段(Phase 1,也叫投票阶段)。
流程是这样展开的:协调者向所有参与者广播 PREPARE 消息;每个参与者执行本地事务的“预操作”——比如在数据库里写入数据、加锁、冻结资源,但不提交;执行成功就回复 YES,失败或资源不足就回复 NO。协调者把这些票收齐,进入汇总等待。一个关键细节是:参与者在执行预操作前,必须先把自己的状态写进磁盘日志(这一点我们留到“日志机制”一节细讲),否则备菜备到一半断电,醒来连自己要干什么都不知道。
用状态机来刻画参与者这一轮的转变:
准备阶段最妙的地方,在于“成本前置”:厨房已经把料备好了,但一切还可以反悔;协调者拿着这张“意向清单”,心里有底了才敢拍板。这正是 2PC 保证原子性的第一道防线。
- 参与者初始状态S_i 表示第 i 个厨房当前所处状态,初始一律为 INIT,表示还没接到这次任务。
- 收到询问后的迁移协调者发出 PREPARE 后,参与者执行备菜动作但先不提交,状态从 INIT 变成 READY(就绪待命)。
- 投出赞成票备菜成功则回复 YES,并把资源锁定给本次事务,不能偷偷干别的。
- 投出反对票备菜失败或资源不足则回复 NO,明确告诉协调者自己无法参与。
提交阶段:一锤定音,全票才上菜
三个厨房的投票收齐后,总管家站在后厨门口,开始做最终裁决。他遵循一条铁律:所有人都说能,才上菜;只要有一个人说不行,全部撤单。不会出现“多数同意就上”——婚宴不是投票选举,一道菜缺席就砸了整场。这就是 2PC 的第二阶段:提交阶段(Phase 2,也叫决策阶段)。
协调者把所有投票做一次“逻辑与”运算:YES 记作 1,NO 记作 0,只有全部为 1,结果才是 1。结果为 1 就广播 COMMIT(提交),结果为 0 就广播 ABORT(中止)。参与者收到指令后执行真正的提交或回滚,然后回复确认应答,协调者收到全部确认后,本次事务才正式关闭。
这一锤落下去,所有厨房才真正把菜端上桌。你看,“全票通过才行动”保证了要么三家同时出菜、要么三家同时撤单,绝不存在“凉菜上了、甜品还没做”的中间态——这正是分布式系统里最看重的原子性。
- 投票编码把 YES 记为 1、NO 记为 0,这样所有票可以用简单的乘法统一处理。
- 逐项相乘把 N 张票全部乘起来,只要出现任何一个 0,最终结果就是 0。
- 提交分支(全票通过)D 等于 1,说明没有反对票,协调者广播 COMMIT。
- 中止分支(任否即止)D 等于 0,说明存在反对票,协调者广播 ABORT,所有人回滚。
超时处理:电话占线怎么办
现实里打电话,最烦的不是对方说“不行”,而是没人接。总管家对着忙音的听筒干等十分钟,后厨的菜已经凉了一半。工程系统必须有“等多久”的答案:协调者给每条消息设置一个超时阈值,超过阈值就不再空等,直接按失败路径处理——通常是广播 ABORT,让所有参与者尽快释放资源。
参与者的处境更微妙。它投完 YES 后,如果协调者迟迟不回复,它不能自己猜“应该提交了吧”然后贸然上菜——因为做错决定会破坏和别的厨房的一致性。正确的做法是:周期性重发询问,请求协调者告知最终决策;同时自己也设一个超时,在超时前保持 READY 状态不变。这就是所谓“延迟待判”:在不知道答案时,维持现状是唯一的诚实选择。
超时是分布式系统里“没有消息就是坏消息”的典型体现。它给了系统一个止损的底线,但也带来误判的可能——电话没接,可能是占线,也可能是对方手机被偷了——单纯凭超时无法区分,所以要靠后面的日志和恢复机制兜底。
- 等待计时T_wait 是发出消息后已经等待的时长,由本地时钟计算得出。
- 超时阈值T_timeout 是预先配置的最大忍耐时长,不同系统按网络状况取值,一般在几百毫秒到几秒之间。
- 超时判定等待时长达到阈值后不再继续空等,转入失败处理分支。
- 角色分工协调者超时倾向于 ABORT,尽快止损;参与者超时则重发询问,等待协调者给出答案。
故障恢复:总管家晕倒之后
最让后厨崩溃的场面是:一切就绪,总管家却突然晕倒了。菜备好了、投票也投了,就是没人下最终指令。2PC 的恢复机制,就是为了应对这种“晕倒”设计的。恢复的起点永远是磁盘上的日志——有人把总管家晕倒前的口令记下来了,继任者才能接着指挥。
节点崩溃重启后,内存全部清空,唯一可信的信息来源是持久化日志。恢复流程分三种情况:日志里最后状态是 INIT,说明还没开始,直接放弃本次事务;最后状态是 COMMIT 或 ABORT,说明决策已定,按决策重放执行并补发确认;最棘手的是疑问状态——日志显示已投 YES(READY),但不知道协调者最终决策,这时参与者只能主动向协调者发起决策查询。协调者若已恢复,会从自己的日志中翻出结果告诉它;若协调者永久宕机,参与者会一直阻塞,直到管理员手工介入。
你可以把恢复机制想象成:厨房墙上贴着一张“本桌菜单进度表”,每次行动前都更新一笔。即使总管家晕倒,新来的管家也能照着表继续指挥——但前提是,这表必须写得够早、够持久。这就引出下一节的主角:日志。
- 恢复入口重启后的节点无法凭内存“回忆”,只能读取磁盘上最后一条日志来恢复状态。
- 合法状态有限日志里允许出现的状态只有四种,任何非法状态都说明日志损坏。
- 疑问状态查询若恢复后发现自己是 READY 且不知道最终决议,就向协调者发起查询。
日志机制:台账必须“先落笔,再干活”
总管家有个职业习惯:每次行动前,先在台账本上写一行“今晚 8 点,通知三个厨房备菜”,然后再去打电话。为什么?因为他知道,人的记忆不可靠,电也会停,只有纸上的字不会消失。分布式系统里的“台账本”,就是预写日志(Write-Ahead Log,WAL):在做任何实质性动作之前,先把打算做的事记录下来。
日志机制有三条铁律。第一,先记后做:日志必须先于动作落盘,绝不能“先干再说”。第二,落盘才算数:日志写进内存缓冲区不算,必须经过 fsync 真正刷到磁盘,才能放心执行动作。第三,幂等重放:同一个日志条目被重放多次,效果和重放一次完全一样,否则恢复时会重复扣款、重复出菜。这三条铁律保证了“崩溃后重建现场”的可靠性。
回到婚宴场景:正是因为有这本台账,总管家才敢自信地打电话——即便中途停电,他醒来翻翻本子就知道“原来我已经通知过三家厨房了”。日志是分布式世界里唯一不会说谎的证人,2PC 的所有恢复逻辑都建立在它之上。
- 先记后做对同一个操作 x,写日志必须发生在执行动作之前,符号 \prec 表示“先于”。
- 落盘才算数日志写进内存缓冲不算完成,必须经过 fsync 持久化到磁盘。
- 可复现状态只要日志完整,任何时刻重放它都能得到确定的最终状态,不会产生二义性。
协议局限:端着菜干等的厨房
任何协议都有代价,2PC 的代价藏在“干等”里。假设总管家已经打完电话、三张 YES 票在手,正要下令上菜时,心脏病发进了 ICU。三个厨房端着备好的菜,走也不是、不走也不是:上菜吧,万一别家没上,宴席更乱;撤吧,万一总管家在抢救前已经吩咐过“上菜”,自己撤了就是偷工减料。于是他们只能端着盘子无限期地等。
这就是 2PC 最著名的阻塞问题:参与者在投出 YES 之后、收到最终决策之前,处于一个“不确定窗口”,此时若协调者崩溃,整个事务被无限期挂起,相关资源全部锁死。更糟的还有单点故障——协调者一挂,全局停摆;脑裂风险——网络分区时,可能出现两个自封的“总管家”发出冲突指令;以及由此产生的不一致窗口,让系统短暂处于“有人提交、有人不知道”的混沌状态。
所以,婚宴总管家这个角色是“成也萧何、败也萧何”:他让三家厨房步调一致,却也把整个晚上的命运押在了他一个人的心脏上。理解了病根,我们才能谈改进。
- 不确定窗口从投出 YES 到收到最终决策之间的时间,是参与者最脆弱的阶段。
- 无限阻塞协调者崩溃且无法恢复时,参与者的等待时长没有上限。
- 脑裂风险网络分区时可能出现两个协调者同时决策,产生冲突指令。
改进演进:三阶段提交与补偿事务
既然 2PC 的病根是“协调者一倒,大家干等”,改进思路自然围绕两点:缩短不确定窗口和弱化协调者的独裁地位。最直接的改良是三阶段提交(3PC):在“询问”和“提交”之间,硬插一轮预提交(Pre-commit)。预提交相当于总管家收到 YES 后,先给每个厨房回一句“大家都说能了,请再次确认,我马上宣布”——参与者收到预提交后,知道自己大概率会被要求提交,提前进入“预备提交”状态。这样即使协调者在预提交后崩溃,参与者也能根据“已进入预提交态”这一线索自主提交,不再无限阻塞。
另一条路是放弃“同步全做”,转向补偿事务(Saga/Compensating Transaction):先把订单创建了,再逐项扣库存、核销优惠券,哪一步失败就反向发补偿消息把前面成功的步骤撤销。这就像婚宴改成“一道道菜陆续上”,哪道菜出了问题,单独撤掉那道菜并给宾客道歉,不必整场重来。此外还有可靠消息方案,用消息队列加对账任务保证最终一致。
没有免费的完美方案:3PC 多了消息量与实现复杂度,补偿事务则牺牲了强一致性,只能保证最终一致。聪明的架构师会像总管家挑酒店一样,看清“这场宴席到底能不能接受某道菜晚到”——强一致场景用 2PC/3PC,高并发场景用补偿与消息,这才是工程权衡的本质。
- 通信轮数R 表示协调者与参与者之间的通信轮数,2PC 是 2 轮,3PC 是 3 轮。
- 每轮消息量每一轮里,协调者向每个参与者发一条、每个参与者回一条,共 2N 条消息。
- 总量对比2PC 总消息 4N,3PC 总消息 6N——3PC 用多一轮的开销,换来了更短的阻塞窗口。
AI 应用场景
跨行转账的清算中心
阶段:分布式事务协调
解决的问题:单库时代转账是一条 SQL 搞定;跨行之后,钱要从 A 银行扣、往 B 银行加,两步分属两个系统,必须“同生共死”。若没有 2PC,一旦扣款成功后到账失败,就是真实的资金损失。清算中心扮演“总管家”,先向两家银行发 PREPARE 冻结资金,两家都冻结成功才 COMMIT 入账。
具体案例:某支付平台日终清算时采用类 2PC 的“双步骤冻结—确认”流程,单笔转账对账延迟从分钟级降到秒级,异常单量下降约 80%。
电商下单的库存与优惠券
阶段:事务方案选型
解决的问题:下单要扣库存、核销优惠券、生成订单,三个服务独立部署。若硬套 2PC,整个事务窗口内库存被锁死,高并发秒杀直接被打垮。因此核心链路改用补偿事务(Saga):先创建订单,再扣库存,若优惠券核销失败,则反向发送“取消订单、回补库存”的补偿消息。
具体案例:某电商大促把订单链路从 2PC 改为“本地消息表 + 异步补偿”,事务响应时间从 800ms 降到 120ms,且能容忍单节点短暂宕机。
分布式数据库的跨节点事务
阶段:存储引擎协调
解决的问题:单机数据库天然有原子性,但分布式数据库要把一行数据拆到多个节点,就必须在引擎层实现 2PC。TiDB 采用 Percolator 风格的两阶段提交:先给主键所在节点写锁,全部加锁成功才提交,并配合 PD 调度器扮演“总管家”角色。
具体案例:某订单系统从分库分表迁移到 TiDB 后,跨分片事务由数据库内置 2PC 接管,应用层不再手写分布式事务,开发与运维成本大幅下降。
Python 演示
import time class Participant: def __init__(self, name, ready=True): self.name = name self.ready = ready self.state = 'INIT' def prepare(self): time.sleep(0.05) if not self.ready: self.state = 'ABORT' print('[%s] 备料失败,投 NO' % self.name) return False self.state = 'READY' print('[%s] 备料完成,投 YES' % self.name) return True def commit(self): self.state = 'COMMIT' print('[%s] 收到 COMMIT,正式出菜' % self.name) def abort(self): self.state = 'ABORT' print('[%s] 收到 ABORT,取消出菜' % self.name) class Coordinator: def __init__(self, participants): self.participants = participants def two_phase_commit(self): print('=== 阶段一:广播 PREPARE 预提交询问 ===') votes = [p.prepare() for p in self.participants] if not all(votes): print('=== 阶段二:存在 NO,广播 ABORT 中止 ===') for p in self.participants: p.abort() return 'ABORT' print('=== 阶段二:全票 YES,广播 COMMIT 提交 ===') for p in self.participants: p.commit() return 'COMMIT' if __name__ == '__main__': happy = [Participant('凉菜厨房'), Participant('热菜厨房'), Participant('甜品厨房')] print('场景一:三家厨房全部就绪') print('最终决议:', Coordinator(happy).two_phase_commit()) print() mixed = [Participant('凉菜厨房'), Participant('热菜厨房', ready=False), Participant('甜品厨房')] print('场景二:热菜厨房备不出菜') print('最终决议:', Coordinator(mixed).two_phase_commit())
votes = [p.prepare() for p in self.participants]相当于总管家给每个厨房打电话预询,把三张票收集成一张清单。if not all(votes):只要清单里出现一个 NO,“全票通过”就不成立,走中止分支。for p in self.participants: p.abort()向所有参与者广播撤单,对应阶段二的 ABORT 指令。for p in self.participants: p.commit()全票通过后广播正式出菜,对应 COMMIT 指令。self.state = 'READY'参与者只备菜不动勺,保持中间状态等待最终指令,这是 2PC 的经典“不确定窗口”。
常见误区
误区我听说 2PC 有超时处理、还有日志恢复,那协调者机器宕机了应该也能马上恢复服务、随时继续提交吧?
正解超时和日志只解决“恢复后有依据”,不解决“恢复期间可用”。协调者崩溃后,所有已投 YES 的参与者只能阻塞等待,既不能提交也不能回滚,业务可用性直接打折扣。真正的高可用要靠协调者主备切换、多副本等外部手段,而不是 2PC 协议本身。
为何常见:把“故障后能恢复”误当成“故障时仍可用”,忽略了恢复需要时间窗口和人工介入。
误区只要准备阶段三个节点都回复 ok,第二阶段广播 COMMIT 后,事务就百分百成功了吧?
正解提交阶段依然可能翻车:某参与者收到 COMMIT 后写日志时磁盘满、进程崩溃,都可能造成它没真正生效。2PC 只保证“要不是全部执行、要不是全部不执行”的决策一致,不保证执行过程零失败;工程上还要配合日志、确认应答与补偿机制。
为何常见:把协议理想化,忽略了提交阶段同样存在落盘和崩溃窗口。
误区协调者广播了 ABORT,说明之前准备阶段做的事都自动没了,系统直接回到最初的干净状态。
正解参与者可能已经在本地执行了部分操作(如冻结资金、占用库存)。ABORT 只是“让每个参与者自行回滚”的命令,回滚本身也可能失败;如果资源已交给外部系统,ABORT 不一定能无损撤销。这就是“补偿不一定可靠”的现实。
为何常见:拿单机数据库回滚的完美直觉,去套分布式系统的不可靠现实。
误区等 5 秒没收到厨房回话,那肯定是厨房出事了,直接把任务取消吧。
正解超时的原因可能是网络延迟、负载抖动,也可能是真崩溃——从“没回复”无法推断分歧。盲目取消可能与对方后续实际提交的动作冲突。可靠做法是配合重试、探活和日志,把“无法判断”的局面交给带状态机的恢复流程去裁决。
为何常见:把分布式网络想象成单机内部总线一样可靠。
误区凡是让多个节点达成一致的协议都能防脑裂,比如选举、多数派,2PC 应该也属于这一类吧?
正解2PC 解决的是“原子提交”而不是“共识”:它没有多数派投票,只有一个协调者说了算。协调者挂掉或网络分区时,系统没有法定多数来继续决策,反而可能脑裂或阻塞。防止脑裂需要 Raft/Paxos 这类共识算法,或退一步用 3PC 缓解阻塞。
为何常见:把“一致性协议”这个大筐里的概念混为一谈,没有区分“原子提交”与“共识”两个不同问题。
面试题
Q1. 两阶段提交的准备阶段中,参与者收到协调者的 PREPARE 询问后,正确做法是什么?
- A.立即执行本地提交并释放全部资源
- B.执行本地事务后先不提交并投票← 正确答案
- C.直接回复 NO 并回滚所有操作
- D.向其他参与者进行同步本地状态
答案:B。准备阶段的核心是“备菜不上桌”:参与者执行本地预操作但不提交,把结果投成 YES/NO 交给协调者汇总。立即提交会让“全票通过再统一行动”失去意义;直接回复 NO 或向他人同步状态都不符合协议规定。
Q2. 若投票阶段有任意参与者回复 NO,协调者在第二阶段应发出什么指令?
- A.忽略 NO 并继续等待其它票
- B.重新询问一遍所有参与者
- C.广播 ABORT 通知参与者停止← 正确答案
- D.强制 COMMIT 让大家提交
答案:C。2PC 的决策规则是“任否即止”:D = v₁ × v₂ × … × vₙ,只要出现一个 0 结果就是 0,协调者广播 ABORT,所有参与者回滚。忽略 NO 或强制提交都会破坏原子性。
Q3. 在 2PC 协议中,拥有最终提交/中止决策权的角色是谁?
- A.各个参与者用投票来决定
- B.最先备好菜的厨房拍板
- C.由数据库底层存储来决定
- D.由唯一的协调者决策拍板← 正确答案
答案:D。协调者(总管家)是全局唯一决策者,参与者只负责投票和执行。多角色投票会导致决策冲突,最先备好菜或存储层拍板在协议中都不存在。|C|=1 保证只有一个口令出口。
Q4. 2PC 的“阻塞问题”指的是什么?
- A.某个参与者投票太慢导致长延时
- B.协调者崩溃后参与者无法决策只能空等← 正确答案
- C.网络带宽不足造成消息排队拥塞
- D.日志文件过大拖慢磁盘写入速度
答案:B。阻塞问题指参与者在不确定窗口内(已投 YES、未收决策)遇到协调者崩溃,既不能提交也不能回滚,等待时间无上限。投票慢和带宽不足是性能问题,不是协议层面的阻塞缺陷。
Q5. 为什么参与者执行本地事务前必须先写日志?
- A.为了让协调者及时知道自己的投票结果
- B.为了让后台监控看到事务的实时状态
- C.为了崩溃后能根据日志恢复本地状态← 正确答案
- D.为了加快事务的提交与执行速度
答案:C。预写日志(WAL)保证“先记后做”:崩溃重启后节点唯一可信的信息来源是磁盘日志,据此恢复 INIT/READY/COMMIT/ABORT 状态。它不是为了通知协调者或加速执行,而是为了可恢复性。
Q6. 2PC 协议的固有局限包括哪些?
- A.协调者单点故障导致全局不可用← 正确答案
- B.参与者存在不确定窗口且可能被阻塞← 正确答案
- C.网络分区时可能产生不一致风险← 正确答案
- D.无法保证任何情况下的数据一致
答案:ABC。单点故障、阻塞、脑裂/不一致窗口是 2PC 公认的三宗罪。但 D 过头了:在协调者不崩溃、网络正常的场景下,2PC 恰恰能保证强一致,所以“任何情况都无法保证”不是它的固有局限。
Q7. 工程实践中常采用哪些措施增强 2PC 的可靠性?
- A.协调者先写预写日志再做决策← 正确答案
- B.参与者和协调者都设置超时重试← 正确答案
- C.为协调者配置主备切换的高可用← 正确答案
- D.取消日志落盘以换取更高的性能
答案:ABC。预写日志让恢复有据可依,超时重试防止消息丢失,协调者主备切换缓解单点故障,三者都是标准增强手段。D 是反向馊主意——去掉落盘会摧毁整个恢复机制。
Q8. 提交阶段协调者广播 COMMIT 后崩溃,某参与者一直未收到决策,它应该怎么办?
- A.默认本次事务直接提交成功
- B.默认本次事务直接回滚处理
- C.反复询问协调者直到得到决策← 正确答案
- D.通知其它参与者自行猜测结果
答案:C。做过本地准备的参与者无法单方面猜提交或猜回滚,否则可能与全局不一致。正确行为是保持 READY 并持续查询协调者/备用协调者,直到拿到明确的 COMMIT 或 ABORT——这正是 2PC 阻塞性的体现。
Q9. 三阶段提交(3PC)对 2PC 的关键改进是什么?
- A.增加预提交轮次以缩小不确定窗口← 正确答案
- B.取消协调者角色改为参与者自治
- C.使用最终一致性替代强一致性
- D.允许参与者提前释放所有资源
答案:A。3PC 在投票与提交之间插入 Pre-commit 轮,让参与者提前进入“预备提交”状态,协调者崩溃后参与者可据此自主决策,大幅缩短阻塞窗口。它没有取消协调者,也没放弃强一致。
Q10. 下列关于 2PC 日志机制的描述,正确的有哪些?
- A.日志必须先于实际操作落盘持久化← 正确答案
- B.崩溃后可按日志重放恢复节点状态← 正确答案
- C.日志属于内存数据无需写入磁盘
- D.重放日志操作应保持幂等性← 正确答案
答案:ABD。WAL 三原则是“先记后做、fsync 落盘、幂等重放”,对应 A、B、D。C 恰好说反——日志如果只在内存里,断电即失,恢复就无从谈起,所以必须持久化到磁盘。