4. 分布式事务与一致性面试题
在金融分布式账务面试中,分布式事务几乎是必问项。面试官真正想确认的不是你能否背出五种方案的名称,而是你能否在资金安全、幂等、补偿、对账这四个约束下,说清楚每种方案的适用边界与落地代价。本章按“核心原理—方法流程—场景案例—误区复盘”四段展开,并给出一张回答框架图,帮助你在面试中快速组织语言。
一、核心原理:五种方案的本质差异
分布式事务的本质是在多个独立资源管理器之间达成状态一致。金融场景下,资源通常是不同库、不同服务甚至不同机构。五种主流方案可归为两类:补偿型(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 我们只在非核心链路试用过,因为全局锁在高峰期会成为瓶颈。”
复盘时建议按“业务边界→一致性要求→方案选型→兜底对账”四步自检。面试中不要只罗列方案,而要说明为什么选它、代价是什么、失败怎么办。能讲清楚补偿与对账,比背出五种方案名称更能体现金融分布式账务的实战能力。