TCC 的三个阶段
TCC(Try-Confirm-Cancel)把分布式事务拆成三段业务操作:Try 检查并预留资源,Confirm 确认使用预留资源,Cancel 释放预留资源。它不依赖数据库的跨库事务,而是把“预留”做成显式的业务状态(冻结额度、占用库存),因此能跨异构系统。代价是业务侵入性强:每个参与方都要实现三种操作,并处理空回滚、悬挂与幂等等边界情况。
基本信息
| Try | 检查并预留资源(冻结额度、占用库存) |
|---|---|
| Confirm | 确认使用预留资源,必须成功且幂等 |
| Cancel | 释放预留资源,需处理空回滚与悬挂 |
| 协调方 | 事务协调器负责记录全局事务状态、发起提交或回滚并做重试 |
典型使用场景
- 跨行转账与结算:账户侧冻结金额,确认后扣减,失败则解冻
- 库存与订单:下单时占用库存,支付成功后扣减,超时未支付则释放
- 优惠券与积分:先锁定券,下单成功再核销,失败退还
- 跨服务的额度控制:先占用授信额度,事后按实际金额结算
- 与外部系统协同:外部系统不支持本地事务时,用两阶段业务操作替代
三阶段状态迁移
三阶段状态迁移
库存:可用 → 冻结(Try)→ 扣减(Confirm)
↘ 释放(Cancel)→ 可用
幂等要点:
- Confirm 重复到达:直接返回成功
- Cancel 先于 Try:记录空回滚标记
- 悬挂 Try:先查空回滚标记再执行异常场景与处理
| 场景 | 表现 | 处理方式 |
|---|---|---|
| 空回滚 | Cancel 在网络超时后先于 Try 到达 | 记录回滚标记,后续 Try 检查标记后直接拒绝 |
| 悬挂 | Cancel 已处理,Try 迟到并执行 | Try 先查回滚标记,存在则不再预留资源 |
| 重复 Confirm | 协调器重试导致 Confirm 多次到达 | 幂等处理,重复请求返回成功 |
| Confirm 失败 | 预留资源无法最终确认 | 重试 + 告警 + 人工介入,不能静默留下冻结资源 |
使用要点
- 把“预留”当成一等业务状态管理:有独立的字段、状态机与对账口径
- Try 阶段就要做业务校验(余额、库存、权限),确认失败要在 Try 阶段就拒绝
- 所有三种操作都要幂等,并记录全局事务 ID 与分支事务 ID 用于对账
- 设置事务超时与最终一致的对账任务:清理长期停留在冻结状态的预留资源
- 为人工介入准备页面或脚本:极端情况下需要人工释放或强制确认
TCC 要把“预留”状态作为一等业务状态管理,并处理 Try 超时未达但 Cancel 先到的悬挂场景;否则会出现资源永久冻结或重复扣减。
TCC 不是唯一选择:业务能容忍延迟或可通过状态机收敛时,本地消息表、可靠事件与对账往往比 TCC 更简单,先在更轻的方案上评估复杂度。