分布式事务的核心问题与一致性模型
微服务架构下,一个业务操作可能涉及多个服务的数据库写入,如何保证这些写入要么全部成功、要么全部回滚,是分布式事务要解决的核心问题。与单机事务不同,分布式事务面临网络分区、节点故障、超时重试等不可控因素,CAP定理决定了在分布式环境下无法同时满足强一致性和高可用性。
工程实践中通常采用最终一致性模型:允许短时间内数据处于不一致状态,通过补偿机制在有限时间内达到一致。目前主流的分布式事务方案有三种:TCC(Try-Confirm-Cancel)、Saga编排和本地消息表+可靠消息。三种方案在一致性强度、实现复杂度和性能开销上各有权衡。
TCC模式的工作原理与实现要点
TCC将一个分布式事务拆分为Try、Confirm、Cancel三个阶段。Try阶段预留资源但不提交,Confirm阶段确认提交,Cancel阶段释放预留资源。TCC的一致性最强——在理想情况下,所有参与者要么Confirm要么Cancel,不存在中间状态。但TCC的实现复杂度也最高,每个服务需要实现三个接口。
TCC的关键实现要点:第一,Try阶段必须做好资源预留,不能直接执行业务逻辑。例如扣减余额的Try操作应该冻结金额(将金额从可用余额转入冻结余额),而不是直接扣减。第二,Confirm和Cancel操作必须幂等,因为协调者在网络超时后会重试。第三,Cancel操作的空回滚处理——如果Try请求因网络原因未到达参与者,协调者发送Cancel时参与者应正常返回而非报错。第四,防悬挂控制——如果Cancel先于Try到达(网络延迟导致),参与者需要记录Cancel已执行,后续Try到达时拒绝执行。
以Seata框架的TCC模式为例,业务接口定义:
@LocalTCC
public interface AccountTccService {
@TwoPhaseBusinessAction(name = "deductBalance",
commitMethod = "confirm", rollbackMethod = "cancel")
boolean deductBalance(BusinessActionContext context,
Long accountId, BigDecimal amount);
boolean confirm(BusinessActionContext context);
boolean cancel(BusinessActionContext context);
}
Saga模式的编排与协同策略
Saga模式将长事务拆分为多个本地事务(Ti),每个本地事务对应一个补偿操作(Ci)。如果第i个本地事务失败,则逆序执行Ci-1到C0的补偿操作。Saga的优势在于每个参与者只需实现业务操作和补偿操作两个接口,实现复杂度低于TCC。但Saga只保证最终一致性——在补偿完成前,已提交的中间状态对其他事务可见。
Saga的两种编排方式:命令式编排(Orchestration)和事件式编排(Choreography)。命令式编排由一个中央协调器(Orchestrator)决定下一个执行步骤,适合流程固定且需要集中控制的场景。事件式编排中每个服务发布事件触发下一个服务执行,适合松耦合、需要灵活扩展的场景。生产环境推荐命令式编排,因为流程状态集中管理,便于排查和重试。
Saga的关键设计点:补偿操作必须幂等;补偿操作本身失败时需要人工介入(记录到异常表中);整个Saga流程需要持久化状态(可恢复),协调器宕机后能从断点继续执行;长Saga流程需要设置超时机制,避免某个参与者无限等待。
本地消息表与可靠消息最终一致性
本地消息表方案的核心思想是:将业务操作和消息发送放在同一个本地事务中,业务数据写入业务表,消息写入消息表,两者在同一个数据库事务中提交。然后由后台任务轮询消息表,将未发送的消息投递到消息中间件(RocketMQ、Kafka)。消费者消费消息执行远程调用,成功后更新消息状态为已完成。
这种方案的优势是实现简单,不需要引入TCC或Saga框架,对业务代码侵入性低。劣势是消息表和业务数据在同一个数据库中,可能影响业务表查询性能,且只支持最终一致性。实现中需要注意:消息表必须包含唯一ID、创建时间、状态(待发送/已发送/已完成/失败)、重试次数等字段;后台轮询任务的间隔需要根据业务容忍度设置(通常1-5秒);消息发送失败需要指数退避重试,超过最大重试次数后标记为死信消息等待人工处理。
CREATE TABLE outbox_message (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
message_id VARCHAR(64) NOT NULL UNIQUE,
topic VARCHAR(128) NOT NULL,
payload TEXT NOT NULL,
status TINYINT DEFAULT 0,
retry_count INT DEFAULT 0,
max_retries INT DEFAULT 5,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
INDEX idx_status_created (status, created_at)
);
三种方案的选型决策矩阵
分布式事务方案选型没有银弹,需要根据业务场景做权衡。决策维度包括:一致性要求(强一致TCC,最终一致Saga/消息表)、业务复杂度(流程长且分支多Saga,流程短且固定TCC)、团队技术储备(低本地消息表,高TCC/Saga)、性能要求(高并发消息表异步,低延迟TCC同步)。
实践经验总结:资金交易类场景(支付、转账)必须用TCC保证资金安全;电商订单类场景(下单、库存扣减)推荐Saga,流程长但允许短暂不一致;通知类场景(发短信、发邮件)用本地消息表即可,对一致性要求最低。一个系统中可能同时使用多种方案,不同模块根据业务特征选择合适的方案。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-shi-wu-jie-jue-fang-an-dui-bi-tcc-saga-yu-ben-di/