一、分布式事务的本质与挑战
在单体应用时代,事务的ACID特性由本地数据库轻松保证。然而随着微服务架构的普及,一个业务操作往往跨越多个服务、多个数据库,分布式事务成为不可避免的技术难题。CAP定理告诉我们,在分区容错性(P)存在的条件下,一致性(C)和可用性(A)不可兼得,这直接催生了多种分布式事务的折中方案。
二、理论基础:从BASE到一致性模型
2.1 ACID的局限性
ACID的原子性在分布式环境下需要协调多参与方的提交/回滚,而网络不可靠性导致两阶段阻塞成为核心痛点。同时,强一致性在分布式场景下必然以牺牲可用性和性能为代价。
2.2 BASE理论
BASE是对CAP中AP方案的一种延伸:基本可用(Basically Available)允许系统在故障时损失部分可用性;软状态(Soft State)允许系统中的数据存在中间状态;最终一致性(Eventual Consistency)保证在没有新更新的情况下数据最终会达到一致状态。
2.3 一致性模型光谱
从强到弱,一致性模型分为:线性一致性、顺序一致性、因果一致性、会话一致性、单调读一致性、最终一致性。不同业务场景对一致性的要求截然不同,电商下单需要因果一致,而社交Feed可以接受最终一致。
三、两阶段提交(2PC):经典方案的深度剖析
3.1 协议流程
两阶段提交引入协调者(Coordinator)角色,分为投票(Voting)和提交(Commit)两个阶段。Phase 1 - Prepare:协调者向所有参与者发送prepare请求,参与者执行事务操作但不提交,将undo/redo日志写入持久化存储,返回Yes/No响应。Phase 2 - Commit/Rollback:若所有参与者回复Yes,协调者发送commit指令;若任一参与者回复No或超时,协调者发送rollback指令。
3.2 阻塞问题与故障场景
2PC的核心痛点在于同步阻塞:参与者在prepare后必须等待协调者的最终决策,期间持有资源锁。若协调者故障且参与者已prepare,参与者陷入阻塞无法释放锁。参与者在prepare阶段超时则默认回滚,但commit阶段参与者故障可能导致协调者与参与者状态不一致。
3.3 工程实践:XA协议
XA是X/Open组织定义的分布式事务接口规范,主流关系型数据库(MySQL InnoDB、PostgreSQL、Oracle)均支持XA。MySQL XA语法包括XA START、XA END、XA PREPARE、XA COMMIT等命令。XA的性能瓶颈在于事务期间的长锁持有,在高并发场景下TP99延迟增加3-5倍,适用于银行转账等强一致性低频场景。
四、三阶段提交(3PC):对2PC的有限改进
3PC在2PC的prepare和commit之间增加了一个preCommit阶段,并引入了超时机制。Phase 1 - CanCommit:协调者询问参与者是否有能力执行事务,不锁定资源。Phase 2 - PreCommit:参与者锁定资源并执行操作但不提交。Phase 3 - DoCommit:协调者发送最终提交指令。改进点在于CanCommit阶段降低了预阻塞时间,参与者在preCommit后若收不到协调者消息会根据超时自动提交。但3PC在网络分区场景下仍可能出现不一致。
五、TCC(Try-Confirm-Cancel):补偿型事务的工程实践
5.1 核心设计思想
TCC将每个分布式操作拆分为三个阶段:Try进行业务资源校验与预留(如冻结账户金额而非直接扣减),Confirm确认执行并基于预留资源完成实际操作,Cancel取消执行并释放预留资源。
5.2 空回滚、幂等、悬挂三大难题
空回滚指Try阶段未执行就直接收到Cancel调用,解决方案是引入事务控制表记录xid,Cancel先查表判断Try是否已执行。幂等问题指Confirm/Cancel可能因网络重试被多次调用,解决方案是在事务控制表中记录执行状态防止重复执行。悬挂指Cancel先执行完成后收到Try请求,解决方案是Try执行时判断对应xid是否已有Cancel记录。
5.3 应用场景
TCC适用于需要强一致性但希望避免长锁持有的场景,如电商下单扣减库存和扣款。其实现复杂度较高,需要在每个业务方法中实现三个接口,并做好三大异常的处理。但相比2PC,TCC没有全局锁的同步阻塞问题,性能更优。
六、可靠消息最终一致性:异步事务模式的工业标准
6.1 本地消息表方案
本地消息表将分布式事务拆解为本地事务加消息投递,业务执行与消息写入在同一个本地事务中完成,确保业务操作成功则消息必定发送。定时任务扫描未发送的消息进行投递,配合指数退避重试策略,消费者端以biz_id作为幂等去重键。
6.2 RocketMQ事务消息
RocketMQ原生支持事务消息的四个阶段:发送半消息对消费者不可见,执行本地事务,根据结果发送commit/rollback给Broker,未收到确认时Broker回查本地事务状态。通过TransactionListener接口的executeLocalTransaction和checkLocalTransaction方法实现。
6.3 最大努力通知方案
适用于对一致性要求可容忍一定延迟但需要保证最佳努力触达的场景,如支付回调通知商户。核心要点是调用方执行本地业务后主动通知,被调用方提供幂等的回调接口,失败时按指数退避重试,超过最大重试后转入人工处理。
七、Saga模式:长事务的编排与协调
7.1 核心原理
Saga将长事务拆分为多个本地短事务(T1到Tn),每个短事务都有对应的补偿操作(C1到Cn-1)。执行顺序为T1到Tn,若Ti失败则逆序执行补偿。实现方式包括编排式(Choreography,事件驱动自发协作)和协调式(Orchestration,中心编排器顺序调用)。
7.2 Saga vs TCC的关键差异
TCC采用两阶段设计(预留+确认),强一致且Try阶段提供较好隔离性,适合短事务强一致场景。Saga采用正向操作加补偿操作设计,最终一致性且无锁,适合长流程跨多服务编排。Saga的中间状态对其他事务可见,存在隔离性缺陷。
7.3 Saga隔离性缺陷与对策
Saga无锁设计导致可能出现脏读和丢失更新。工程对策包括语义锁(业务层标记进行中状态)、交换式更新(设计为可交换的操作如金额增减)、悲观视图(将待读取数据视为不可靠并选择保守决策)。
八、Seata框架:一站式分布式事务解决方案
8.1 四种事务模式
Seata提供AT、TCC、SAGA、XA四种模式的统一封装。AT模式基于undo log自动补偿,对业务无侵入,默认推荐。TCC需要业务实现三个接口。SAGA基于状态机管理长事务。XA基于数据库原生XA协议,强一致但性能较低。
8.2 AT模式原理详解
AT模式在业务SQL执行前后自动生成undo log,实现自动补偿。流程为:解析SQL提取前后镜像,将undo log写入与业务同库同事务的undo_log表,提交前向TC注册分支事务获取全局锁。全局事务成功则清理undo log失败则执行undo log回滚。AT性能优于2PC因为本地锁提交时立即释放。
8.3 生产部署架构
TC Server以集群部署,使用DB存储全局事务和分支事务信息。Registry和Discovery支持Nacos等注册中心。Session存储生产推荐DB或Redis模式。核心表包括global_table、branch_table、lock_table、distributed_lock。
九、选型决策树与最佳实践
跨服务短事务首选AT模式(Seata)或XA强一致方案,若不接受短锁则选TCC模式。长流程编排选Saga模式。可接受秒到分钟级延迟选可靠消息最终一致性方案。低要求场景选最大努力通知。
实际生产中的组合方案包括:电商下单使用TCC冻结库存加本地事务创建订单加MQ异步通知、银行转账核心链路用2PC或AT且跨行清算异步对账、物流调度用Saga编排每步设计补偿操作。
十、总结
分布式事务没有银弹。工程实践核心原则是避免不必要的分布式事务,优先服务合并,缩短事务链路长度,在一致性要求上做减法。最务实的策略是最终一致性为主,强一致性兜底。关键路径用TCC或AT保障资金安全,非关键路径用消息异步兜底,通过监控和告警及时发现不一致并介入修复。随着NewSQL如TiDB和CockroachDB的成熟,更多分布式事务将下沉到数据库层解决,应用侧复杂度有望进一步降低。

发表评论 取消回复