跳到主要内容

2PC、TCC 与协调成本

2PC 让多个事务资源对同一个提交决定达成一致,TCC 则把预留、确认和取消提升到业务层。两者都需要协调器记录全局状态,并处理参与者超时后的结果不确定。

1. 2PC 的第一阶段准备提交

协调器向所有参与者发出 prepare。参与者完成约束检查、写入足够的持久恢复信息,并承诺之后能够按协调器决定 commit 或 rollback。

成功 prepare 后,参与者通常仍要保留锁或其他事务资源。它不能自行改变决定,因为其他参与者可能已经准备成功。

只要一个参与者明确拒绝 prepare,协调器就记录 abort 决定并通知所有已准备参与者回滚。

2. 第二阶段传播最终决定

全部参与者 prepare 成功后,协调器持久记录 commit 决定,再通知各参与者提交。通知可能丢失,所以参与者和协调器都要在重启后从日志恢复,并重复传播或查询决定。

协议不能消除网络分区。参与者已 prepare、却无法取得最终决定时,可能必须保持资源等待协调恢复。2PC 用可用性和锁持有时间换取受控资源内的原子提交。

3. 2PC 需要资源管理器原生支持

XA、数据库 prepared transaction 等能力让资源管理器在进程重启后继续记住准备状态。普通 HTTP 接口即使提供“先调用、后确认”两个方法,也不会自动获得同样的隔离和恢复语义。

参与者数量、跨地域延迟和协调器日志都会进入提交路径。适合短事务和少量受控资源,不适合把人工审批、长时间外部调用一直锁在准备阶段。

4. TCC 的 Try 显式预留业务资源

TCC 为每个参与者设计:

  • Try:检查条件并预留额度、库存或席位。
  • Confirm:使用已预留资源完成业务。
  • Cancel:释放预留或恢复业务状态。

Try 通常提交一个本地事务,所以预留状态会对其他请求可见。它避免长时间持有数据库事务锁,但需要业务模型支持“冻结”“待确认”等中间状态。

5. Confirm 和 Cancel 必须幂等

协调器收不到响应时会再次调用。Confirm 重复不能再次扣款,Cancel 重复也不能多次释放额度。参与者使用全局事务 ID 和分支 ID 记录执行状态,并通过条件转换保证只推进一次。

Confirm 原则上只消费 Try 已预留的资源,不再执行可能失败的新业务检查。否则全局决定提交后,某个参与者仍可能因条件变化无法确认。

6. 空回滚和悬挂需要专门处理

网络乱序时,Cancel 可能先于延迟到达的 Try。参与者应记录这次分支已经取消,即使之前没有预留,这称为空回滚处理。迟到的 Try 看到取消标记后必须拒绝,避免 Cancel 完成后又创建预留,这类情况通常称为悬挂。

这些状态要保留足够时间覆盖协议重试,并由唯一键保证并发处理原子性。

7. TCC 的成本进入每个业务参与者

每项资源都要设计 Try、Confirm、Cancel、状态表、超时释放和审计。资源预留会降低可售或可用数量,协调器故障时可能长时间占用。

外部系统若不支持预留和幂等确认,就不能靠调用方包装三个方法获得可靠 TCC。此时要选择 Saga、异步事件或人工处理风险。

8. 选择取决于资源和业务语义

2PC 适合支持事务协议、事务短且强原子性价值高的少量资源;TCC 适合能够显式预留,并愿意承担业务侵入的关键流程。两者都要:

  • 协调器持久化全局决定。
  • 参与者可重入、可恢复。
  • 监控长期 prepared 或 reserved 状态。
  • 提供超时、核对和人工解除入口。

9. 常见问题

9.1 协调器高可用后,2PC 是否就不阻塞

不会完全消除。网络分区或参与者无法联系协调器时,已 prepare 的事务仍可能等待最终决定。高可用缩短协调器单机故障,不改变协议在不确定状态下保守等待的要求。

9.2 TCC 的 Cancel 是否等于数据库 rollback

不等于。Try 已经提交本地事务,Cancel 是新的业务事务,用显式逻辑释放预留。它可能失败并需要幂等重试,也可能无法完全恢复外部世界。

10. 面试题

10.1 2PC 和 TCC 的差异是什么,各自有哪些失败状态

出现公司:阿里巴巴

考察重点

  • prepare、持久决定和不确定等待。
  • Try 预留、Confirm/Cancel 幂等。
  • 空回滚、悬挂、资源持有和恢复。

相关内容:第 1 节“2PC 的第一阶段准备提交”至第 8 节“选择取决于资源和业务语义”。

参考回答

2PC 由资源管理器原生支持。第一阶段参与者 prepare 并持久承诺可提交,通常继续持锁;全部成功后协调器持久记录 commit 决定并在第二阶段通知。参与者 prepare 后无法取得决定时可能阻塞,因此提交延迟、资源占用和协调恢复都是成本。

TCC 把协议放到业务层:Try 提交本地预留,Confirm 消费预留,Cancel 释放预留。Confirm 和 Cancel 必须幂等,还要处理 Cancel 先到的空回滚,以及迟到 Try 不能再预留的悬挂。它减少长期数据库锁,却要求每个参与者实现中间状态、超时释放和审计。选择取决于资源是否支持事务协议或业务预留,而不是只比较性能名词。