4. 分布式事务与一致性面试题

在金融分布式账务面试中,分布式事务几乎是必问项。面试官真正想确认的不是你能否背出五种方案的名称,而是你能否在资金安全、幂等、补偿、对账这四个约束下,说清楚每种方案的适用边界与落地代价。本章按“核心原理—方法流程—场景案例—误区复盘”四段展开,并给出一张回答框架图,帮助你在面试中快速组织语言。

分布式事务回答框架:先定边界,再选方案 业务边界 资金/非资金 一致性要求 强一致/最终一致 方案选型 TCC/SAGA/消息 兜底 对账+补偿 追问路径: 1. 为什么不用XA?→ 锁资源、性能差、跨DB不友好 2. TCC空回滚/悬挂怎么解?→ 防悬挂表+状态机 3. 消息表如何保证不丢?→ 本地事务+定时补偿+对账

一、核心原理:五种方案的本质差异

分布式事务的本质是在多个独立资源管理器之间达成状态一致。金融场景下,资源通常是不同库、不同服务甚至不同机构。五种主流方案可归为两类:补偿型(TCC、SAGA)和消息型(本地消息表、最大努力通知、Seata AT 的全局锁+回滚日志)。

  • TCC:Try 预留资源、Confirm 确认、Cancel 补偿。强侵入,需业务实现三个接口,适合资金冻结、库存扣减等短事务。
  • SAGA:长事务拆成多个本地事务,每个配一个补偿动作。适合跨服务长流程,如开户+绑卡+风控。
  • 本地消息表:业务与消息写入同一本地事务,异步投递,消费方幂等。适合最终一致、允许延迟的场景。
  • 最大努力通知:通知方不断重试,接收方幂等处理,不保证一定成功,需对账兜底。适合外部渠道回调。
  • Seata:AT 模式通过 undo_log 自动回滚,对业务侵入小;TCC/SAGA 模式则需手动实现。金融核心账务更倾向 TCC 或消息表。

二、方法流程:以 TCC 与本地消息表为例

TCC 的标准流程是:Try 阶段检查并预留资源,Confirm 阶段确认扣减,Cancel 阶段释放预留。关键点在于幂等、空回滚、防悬挂。空回滚指 Try 未执行而 Cancel 先到;悬挂指 Cancel 先于 Try 执行。解决方案是引入事务状态表,记录全局事务 ID 与分支状态。

-- TCC 防悬挂与空回滚状态表
CREATE TABLE tcc_transaction (
  tx_id        VARCHAR(64) PRIMARY KEY,
  branch_id    VARCHAR(64),
  status       TINYINT,  -- 0:TRY 1:CONFIRM 2:CANCEL
  create_time  DATETIME,
  update_time  DATETIME
);

-- Cancel 前先查状态:若不存在则插入 CANCEL 记录,防止后续 Try 悬挂
INSERT INTO tcc_transaction(tx_id, branch_id, status)
VALUES('TX001','BR001',2)
ON DUPLICATE KEY UPDATE status = 2;

本地消息表的流程是:业务操作与消息记录在同一本地事务中提交,然后由定时任务或事务消息投递到 MQ,消费方幂等消费,失败则重试,最终由对账系统兜底。核心表结构如下:

CREATE TABLE local_message (
  id           BIGINT AUTO_INCREMENT PRIMARY KEY,
  biz_id       VARCHAR(64),
  topic        VARCHAR(64),
  payload      TEXT,
  status       TINYINT,  -- 0:待发送 1:已发送 2:已消费
  retry_count  INT DEFAULT 0,
  next_retry   DATETIME,
  create_time  DATETIME
);

三、场景案例:跨行转账与积分发放

场景一:跨行转账。A 行扣款、B 行入账,属于跨机构资金流转。此时 TCC 需要双方都支持 Try/Confirm/Cancel,成本高;更常见的是本地消息表+对账:A 行扣款后写消息,B 行消费入账,日终对账发现不一致再人工或自动补偿。若监管要求强一致,则需接入人行清算系统,而非自研分布式事务。

场景二:支付成功后发放积分。支付是核心链路,积分是旁路。适合本地消息表或最大努力通知:支付成功写消息,积分服务异步消费,失败重试,允许最终一致。若积分发放失败,不影响支付结果,但需告警与补发。

方案一致性侵入性适用场景金融落地建议
TCC强一致高资金冻结、库存核心账务,需状态机
SAGA最终一致中长流程编排开户、风控流程
本地消息表最终一致低异步解耦积分、通知、对账
最大努力通知最终一致低外部回调渠道通知,需对账
Seata AT强一致低同库多服务非核心链路,注意全局锁

四、误区复盘与面试表达

误区一:认为 Seata AT 可以无脑用于资金场景。AT 依赖全局锁和 undo_log,高并发下锁冲突严重,且回滚是“反向补偿”,并非真正回滚。资金场景更应使用 TCC 或消息表。

误区二:忽略幂等与空回滚。面试官常追问“Cancel 比 Try 先到怎么办”,若答不出状态表或防悬挂机制,会被判定为只背概念。

误区三:把最大努力通知当成可靠消息。它不保证成功,必须配合对账与人工兜底,否则资金会丢。

面试表达模板:“我们账务系统对资金一致性要求高,所以核心扣减用 TCC,Try 冻结、Confirm 扣减、Cancel 解冻,并用事务状态表解决空回滚和悬挂;旁路积分用本地消息表,业务与消息同事务提交,定时任务投递,消费方幂等,日终对账兜底。Seata AT 我们只在非核心链路试用过,因为全局锁在高峰期会成为瓶颈。”

复盘时建议按“业务边界→一致性要求→方案选型→兜底对账”四步自检。面试中不要只罗列方案,而要说明为什么选它、代价是什么、失败怎么办。能讲清楚补偿与对账,比背出五种方案名称更能体现金融分布式账务的实战能力。