第三章 分布式事务与一致性方案:高频问题、回答框架、公司侧重点
本章核心命题:在跨服务、跨数据库的支付链路中,如何保证数据最终一致?面试官重点关注你对 TCC、Saga、本地消息表、Seata AT 等方案的选型判断力、异常处理设计以及幂等与防悬挂的落地细节。
面试加分点:引用“最大努力通知”与“可靠消息”的差异,以及支付宝、微信支付内部常用“TCC + 消息对账”的组合方案。
问答卡片 3-1:TCC 事务的空回滚与防悬挂
| 面试问题 | TCC 的空回滚和防悬挂是什么?如何实现? |
| 考察点 | 是否理解 TCC 执行时序异常;幂等设计能力;事务协调器与资源管理器的交互细节。 |
| 回答框架 |
|
| 示例回答 | “空回滚指 Try 未成功但收到 Cancel,需在 Cancel 方法中判断本地事务是否已预留资源,若无则直接返回成功。防悬挂指 Cancel 先于 Try 到达,需在 Try 入口检查是否已存在 Cancel 记录,如果存在则忽略 Try 操作并返回成功,避免资源被无效预留。” |
| 可能追问 |
|
| 避坑提醒 | 切忌只背概念,必须结合代码或配置举例。防悬挂常被遗忘,是区分初级与高级的关键点。 |
问答卡片 3-2:Saga 与 TCC 的选型对比
| 面试问题 | 你们的支付业务为什么选 Saga 而不是 TCC? |
| 考察点 | 方案选型判断力;对业务隔离性需求的认知;对补偿/回滚成本的权衡。 |
| 回答框架 |
|
| 示例回答 | “我们选 Saga 是因为支付→出库→物流流水线超过 5 个节点,TCC 的 Try 阶段要冻结库存和余额,冻结时间过长会导致资金利用率下降。Saga 通过状态机 + 补偿表,在出错时回滚已完成步骤,更符合我们的长事务场景。” |
| 可能追问 |
|
| 避坑提醒 | 避免化说法,如“TCC 一定更好”。要结合业务特点(隔离需求、事务时长、团队能力)说明理由。 |
问答卡片 3-3:本地消息表 vs 事务消息
| 面试问题 | 你们在支付对账场景中,为什么用 RocketMQ 事务消息而不是本地消息表? |
| 考察点 | 方案优缺点对比;消息中间件特性理解;对运维成本和一致性的权衡。 |
| 回答框架 |
|
| 示例回答 | “我们选择 RocketMQ 事务消息,因为支付成功通知需要在 1 秒内到达下游。本地消息表定时扫表间隔至少 5 秒,不满足延迟要求。事务消息在半消息 commit 后立即投递,配合回查接口保证最终一致。” |
| 可能追问 |
|
| 避坑提醒 | 不要只说“事务消息更好”,要提及其依赖 MQ 服务稳定性、回查接口的可达性,以及半消息超时清理问题。 |
项目案例:资金账户聚合转账 —— TCC 分布式事务落地
| 项目名称 | 聚合支付网关-账户间转账 TCC 改造 |
| 业务背景 | 用户从 A 银行卡转账至 B 平台余额,需经过:渠道方扣款 → 平台入账 → 通知三方。三个子系统独立部署,必须保证“扣款成功”与“入账成功”严格一致。 |
| 规模指标 | 日均交易 50 万笔;单笔金额上限 5 万;P99 延迟 < 800ms;要求数据最终一致窗口 < 30s。 |
| 技术栈 | Spring Boot + Seata (TCC 模式) + Redis (分布式锁 + 幂等表) + MySQL (分库分表) + RocketMQ (失败重试/补偿通知) |
| 核心难点 |
|
| 面试高频追问 |
|
| 可迁移回答话术 |
“我们在 Try 阶段为每个资源设置全局事务 ID 和状态字段,Cancel 时先检查状态,避免重复回滚。同时设计了一个轻量级调度任务,定期扫描处于‘悬挂’状态的事务,执行人工介入或自动补偿。”
|
本章面试特别提示:不同大厂侧重点略有差异:阿里系偏好 TCC + Seata,常深挖二阶段异常处理;美团/字节更关注 Saga 与消息对账的工程落地;支付类外企强调分布式事务原理(如 CAP、BASE)与 Paxos/Raft 的关联。准备时,三个方向都要覆盖 1-2 个真实案例。