题目:TCC 中,Confirm 或者 Cancel 失败了怎么办?
难度:medium
评分:⭐⭐⭐☆☆
PEC 的提交或者回滚如果失败了,主流程第一个应该是记录,把这个事情整个记录下来,然后进行尝试,尝试重试,如果还是不行的话,就进行人工告警,消息告警,告警到人工去进行记录处理、接入处理。
评分:⭐⭐⭐☆☆
优点:
不足:
补充:
核心考点定位:考察对 TCC 框架"失败处理机制"的完整认知——不止"重试+人工",还要覆盖幂等、空回滚、悬挂三大坑。
知识点拆解:
1. 失败记录:写失败日志 + 更新事务状态表(FAILED)
2. 幂等重试:定时任务扫 FAILED → 基于业务单号幂等执行
3. 超时兜底:重试 N 次仍失败 → 标记 NEED_MANUAL
4. 告警通知:短信/钉钉/飞书通知值班
5. 对账巡检:日终对账系统兜底,发现不一致生成差错账
6. 人工介入:工程师查失败现场,手工补偿
txn_id)建唯一键,重复请求直接返回上次结果| 坑 | 触发条件 | 表现 | 解决 |
|---|---|---|---|
| 空回滚 | Try 未执行,Cancel 到达 | Cancel 操作不存在的资源 | Try 标记表检查,未 Try 则 Cancel 直接成功 |
| 幂等 | Confirm/Cancel 重试 | 重复扣款/发货 | 三方法都基于业务单号做幂等 |
| 悬挂 | Confirm 先到被拒,Try 后到 | 资源被 Try 占用但事务已判失败 | Try 前检查事务状态,已确认/已取消则拒 Try |
queryConfirmStatus(txn_id))考察方向:
延伸递进面试题:
queryConfirmStatus 接口;业务方要实现状态查询接口面试官您好,TCC 的 Confirm 或 Cancel 失败处理,我一般按"自动恢复 + 人工兜底"两条链路设计。 自动恢复链路分三步: 1. 失败记录:把失败现场写到事务状态表,状态标记为 FAILED,记录失败原因、尝试次数 2. 幂等重试:定时任务扫描 FAILED 状态的事务,调用 Confirm/Cancel 重试。但这里有个关键点——Confirm 和 Cancel 必须幂等,因为重试会多次执行,如果不幂等就会重复扣款、重复发货。实现方式是基于业务单号建唯一键,重复请求直接返回上次结果 3. 超时兜底:重试 3-5 次仍失败,标记为 NEED_MANUAL,进入告警链路 人工兜底链路分三步: 1. 告警通知:通过短信/钉钉/飞书通知值班工程师 2. 对账巡检:日终对账系统扫描所有事务状态,发现不一致生成差错账,这是最后一道防线 3. 人工介入:工程师查失败日志、事务状态表、资源状态,手工补偿 这里还有个关键——TCC 有三大坑必须同时处理: - 空回滚:Try 因网络问题从未执行,但 Cancel 因协调者崩溃恢复而到达。解决:在 Try 标记表检查,未 Try 则 Cancel 直接返回成功 - 幂等:Confirm/Cancel 重试。解决:三个方法都必须基于业务单号做幂等 - 悬挂:Confirm 先到达被拒绝(无 Try 记录),随后 Try 才到,资源被 Try 占用但事务已判失败。解决:在 Try 前检查事务状态表,已确认/已取消则拒绝 Try Seata TCC 框架已经自动处理了这三大坑,但业务自建 TCC 一定要自己处理。另外,Seata 还有"超时回查"机制——TC 会定期回查分支事务状态,业务方需要实现一个状态查询接口,告诉 TC "我到底成功了没有"。 工程最佳实践:Confirm/Cancel 失败重试建议 3-5 次,间隔指数退避(1s → 2s → 4s);告警要分级,普通失败走钉钉,超时失败走电话/短信;对账系统是终极兜底,TCC 不是 100% 可靠,极端故障下靠对账发现不一致。 总结一句话:重试的前提是幂等,幂等的前提是三大坑都处理好,三大坑处理好的前提是业务方愿意投入。这也是为什么核心业务往往用 Seata TCC 而不是自建 TCC。