Skip to content

微服务架构下事务一致性治理的客观分析

概览

从 XA、2PC、Saga、TCC、本地消息表、Transactional Outbox、幂等、领域边界和对账补偿等角度,分析现代微服务为什么不再默认使用传统强一致分布式事务。

摘要

微服务架构将业务系统拆分为多个自治服务,每个服务通常拥有独立的数据模型、独立数据库和独立发布生命周期。该架构提高了服务自治性、技术栈灵活性和故障隔离能力,但也使跨服务数据一致性问题从单库 ACID 事务转变为分布式一致性问题。早期工程实践中,部分团队尝试将单体数据库中的事务模型迁移到微服务体系中,使用 XA 或 2PC 协议保证跨服务强一致性。然而,2PC/XA 的协调者、参与者、Prepare、Commit/Rollback 等机制会引入资源持有、事务悬挂、协调器依赖和链路耦合等问题。现代微服务治理通常不再将传统分布式事务作为默认方案,而是优先通过领域边界划分、本地事务、幂等、消息驱动、对账补偿、Saga 与 TCC 等方式实现可接受的一致性模型。

关键词:微服务;分布式事务;XA;2PC;Saga;TCC;最终一致性;本地消息表;幂等性;领域驱动设计


1. 引言

在单体应用中,多个业务操作通常共享同一个数据库实例和同一个事务上下文,因此可以直接依赖数据库事务提供原子性、一致性、隔离性和持久性。进入微服务架构后,服务被拆分为多个自治单元,数据也随服务边界分散。Microsoft 的微服务数据治理文档明确指出,每个微服务管理自己的数据,因此数据完整性和一致性会成为微服务架构中的关键挑战;其 .NET 微服务架构指南也强调,每个微服务必须拥有自己的领域数据和逻辑,并在自治生命周期内独立部署。(Microsoft Learn)

传统 XA/2PC 试图在多个资源管理器之间恢复单体事务的强一致语义。MySQL 官方文档描述了 XA 全局事务使用两阶段提交:第一阶段所有分支被要求进入 prepared 状态,第二阶段根据第一阶段结果执行提交或回滚。PostgreSQL 官方文档同样说明,2PC 通过 PREPARE TRANSACTIONCOMMIT PREPAREDROLLBACK PREPARED 等命令实现,并用于外部事务管理系统协调多个分布式系统。(MySQL开发者专区)

因此,问题的核心并不是“分布式事务是否存在价值”,而是“传统强一致分布式事务是否适合作为微服务系统的默认一致性手段”。从现代微服务治理实践看,答案通常是否定的。


2. 传统分布式事务的机制基础

XA/2PC 的基本模型由事务管理器和多个资源管理器构成。事务管理器负责协调全局事务,资源管理器负责执行各自的本地事务分支。两阶段提交一般分为两个阶段:

第一阶段是 Prepare 阶段。协调者要求所有参与者准备提交。MySQL 文档说明,在这一阶段,每个资源管理器通常需要把分支事务的动作记录到稳定存储中,并向事务管理器报告是否可以提交。(MySQL开发者专区)

第二阶段是 Commit/Rollback 阶段。如果所有参与者都准备成功,协调者通知各参与者提交;如果任一参与者失败,则协调者通知各参与者回滚。PostgreSQL 文档指出,prepared transaction 的状态会存储到磁盘,并且在之后由 COMMIT PREPAREDROLLBACK PREPARED 完成最终处理。(PostgreSQL)

这种机制在理论上可以提供跨资源的原子提交能力,但其代价是所有参与者必须在全局事务完成前维持可恢复状态,并依赖协调器推进最终决议。PostgreSQL 官方文档还明确建议,prepared transaction 通常应在外部事务管理器确认其他数据库也准备好提交后尽快提交或回滚;如果没有外部事务管理器跟踪并及时关闭 prepared transaction,最好将 max_prepared_transactions 设置为 0,以防止被遗忘的 prepared transaction 最终造成问题。(PostgreSQL)


3. 微服务架构下传统 2PC/XA 的主要冲突

3.1 性能瓶颈:全局提交路径拉长了资源占用时间

2PC 把一次业务操作拆成 Prepare 与 Commit/Rollback 两个全局协调阶段。与单库本地事务相比,它增加了跨网络通信、事务状态持久化、协调器调度和参与者等待时间。数据库事务本身就依赖锁或版本控制维护隔离性;Microsoft SQL Server 文档也指出,在多用户系统中,事务管理不当通常会导致争用和性能问题,随着并发访问用户增多,应用必须有效控制事务。(Microsoft Learn)

在高并发微服务链路中,如果订单、库存、积分、支付等多个服务共同进入同一个 XA/2PC 全局事务,那么任何一个服务、数据库或网络节点变慢,都会拉长整个全局事务的完成时间。prepared transaction 不能无限期悬挂,PostgreSQL 官方文档要求其通常应尽快提交或回滚,并建议在没有事务管理器时禁用 prepared transaction,原因正是遗留的 prepared transaction 会带来后续问题。(PostgreSQL)

因此,传统 2PC/XA 在高并发微服务系统中的主要性能问题不是单次 SQL 慢,而是全局链路中最慢参与者决定整体资源释放时间。这会把局部抖动传播为全局延迟,把单点慢查询放大为跨服务吞吐下降。

3.2 可用性冲突:一个参与者异常会影响整个全局事务

微服务架构强调服务自治和故障隔离。Azure 微服务架构文档将微服务定义为一组小型自治服务,每个服务自包含,并在有界上下文内实现单一业务能力。(Microsoft Learn)

2PC/XA 的设计目标则是让多个资源在同一个全局事务中共同提交或共同回滚。该机制天然要求所有参与者在全局事务边界内协同完成。如果一个参与者不可用、响应超时或提交结果不确定,全局事务就会进入等待、恢复或人工介入路径。这与微服务希望通过服务边界隔离故障影响范围的目标存在结构性冲突。

更准确地说,2PC/XA 并不是不能用于微服务,而是会把多个自治服务重新绑定成一个强耦合提交单元。服务数量越多、链路越长、异构资源越多,全局事务的可用性就越接近所有参与者可用性的乘积,而不是单个服务的可用性。

3.3 数据自治冲突:数据库私有原则被削弱

微服务的数据治理通常强调 “Database per Service”。Microservices.io 将其描述为每个服务持有私有持久化数据,可以表现为私有表、私有 schema 或独立数据库服务器。(microservices.io)

如果多个微服务通过一个全局事务协调器共享提交边界,虽然物理数据库仍然独立,但业务上已经形成跨服务提交耦合。服务之间不再只通过 API、事件或契约协作,而是通过全局事务生命周期绑定在一起。这种绑定会削弱服务自治性,使服务拆分从运行时角度退化为“分布式单体”:代码分散、数据库分散、部署分散,但失败域和提交路径仍然紧密耦合。

3.4 运维复杂度:prepared transaction 需要外部治理

prepared transaction 不是普通本地事务。PostgreSQL 官方文档说明,PREPARE TRANSACTION 不是面向应用或交互式会话的普通命令,而是面向外部事务管理器,用于跨多个数据库或事务资源原子提交。(PostgreSQL Japan)

这意味着 XA/2PC 不仅是开发框架问题,也是运维治理问题。系统必须具备事务协调器、事务日志、超时恢复、悬挂事务扫描、参与者恢复、幂等提交/回滚、监控告警和人工修复流程。缺少这些治理能力时,传统分布式事务会从“一致性保障手段”变成“故障恢复复杂度来源”。


4. 现代微服务治理如何消灭或规避分布式事务

现代微服务治理的基本策略不是在所有跨服务操作上套全局事务,而是先降低产生分布式事务的概率,再对剩余场景选择更合适的一致性机制。

4.1 通过领域驱动设计与服务边界划分减少跨服务写事务

Azure 微服务架构文档指出,微服务应该围绕有界上下文实现单一业务能力;每个微服务管理自己的领域数据和逻辑。(Microsoft Learn)

在事务治理上,这意味着服务划分不应只按技术模块拆分,而应按业务不变量和一致性边界拆分。强一致约束应尽可能被放入同一个聚合、同一个服务和同一个本地事务中。例如,订单状态流转、订单明细写入、订单创建流水,如果属于同一订单聚合,就不应拆到多个服务中再依赖分布式事务拼接。

这种做法的客观效果是:把强一致需求压缩在本地事务边界内,把跨服务协作转化为事件通知、状态同步、读模型更新或补偿流程。

4.2 使用本地事务、幂等性与分布式锁处理单边一致性问题

对于库存预占、优惠券领取、防重复提交、任务抢占等单边操作,很多场景并不需要 XA/2PC。更常见的做法是使用本地事务保证单服务内部原子性,再通过幂等键、唯一索引、请求号、状态机和必要的分布式锁控制并发。

Redis 官方文档提供了基于 Redis 的分布式锁算法说明,其目标是为分布式环境中的共享资源访问提供互斥能力。(Redis)

但分布式锁不能替代分布式事务。它适合保护临界区或避免重复并发执行,不负责在多个服务数据库之间自动回滚。因此,在工程实现中,锁必须和幂等设计共同使用。Azure API 设计文档指出,幂等操作可以被多次调用而不会在第一次调用之后产生更多副作用,并且幂等性是上游服务安全重试的重要韧性策略。AWS Builders’ Library 也专门讨论了 Amazon 如何使用幂等 API 让重试更安全。(Microsoft Learn)

因此,单边操作的治理重点不是引入全局事务,而是:本地事务负责状态变更,唯一约束负责防重,幂等键负责重试安全,分布式锁只在确有共享资源竞争时控制并发窗口。

4.3 使用本地消息表或 Transactional Outbox 解决数据库与消息双写

跨服务异步协作中,一个常见问题是“数据库写成功但消息发送失败”,或“消息发送成功但数据库回滚”。AWS Prescriptive Guidance 将 Transactional Outbox 模式定义为解决分布式系统中数据库写入与消息/事件通知双写问题的模式。该模式把业务数据和 outbox 事件写入同一个数据库事务,然后由独立发布器异步投递事件。(AWS 文档)

该模式的关键不是保证所有服务同步提交,而是保证本服务的状态变更和事件记录在同一个本地事务中原子完成。下游服务通过消息消费、幂等处理、重试和补偿达到最终一致。这类方案适合订单创建后通知积分、风控、营销、搜索索引、日志分析、数据仓库等不需要同步强一致的场景。

4.4 使用对账系统与人工兜底处理最终最终一致性

在金融、支付、电商、物流等业务中,即使采用 Saga、TCC、消息表、事务消息,也无法消除所有异常:网络分区、重复消息、超时未知、第三方回调丢失、人工退款、系统重放都可能产生状态差异。因此,对账系统并不是低级兜底,而是最终一致性架构的组成部分。

对账系统通常基于业务流水、状态机、审计日志、资金流水、库存流水、支付渠道账单等进行周期性比对,并将不可自动修复的差异进入人工工单或运营处理流程。该机制对应的是“最终最终一致性”:在线链路尽可能自动收敛,离线或准实时对账负责发现并修正残余异常。


5. 分布式事务在今天仍然存在的必要场景

虽然现代微服务治理通常避免默认使用传统分布式事务,但这不代表所有跨服务一致性都可以被简单异步化。在核心金融、支付、账户余额、库存预占、积分扣减、复杂电商下单等场景中,业务后果直接涉及资产、履约和用户权益,不能仅依赖“失败后随缘修复”。

典型链路如下:

text
用户下单支付链路:
1. 订单服务:创建订单
2. 积分服务:扣减积分
3. 仓储服务:预扣库存
4. 支付服务:扣除账户余额

这些服务通常不能简单合并为一个单体,因为它们分别承担不同领域能力,并拥有独立数据模型、权限边界、扩展需求和发布周期。但如果积分已扣减、库存预扣失败、支付状态未知,系统就必须提供确定的补偿、冻结、回滚、解冻、重试或人工处理机制。

因此,在这类场景中,事务治理的目标不是回到传统 XA/2PC,而是在业务可接受的范围内选择柔性分布式事务。Apache Seata 官方文档说明,Seata 提供 AT、TCC、Saga 和 XA 等事务模型,用于构建一站式分布式事务解决方案。(Seata)


6. 柔性分布式事务模式:Saga 与 TCC

6.1 Saga 模式:长事务拆分为本地事务与补偿事务

Azure Architecture Center 将 Saga 定义为一种在分布式系统中维护数据一致性的设计模式。Saga 由一系列本地事务组成,每个服务完成自己的本地事务,并通过事件或消息触发下一步;如果某一步失败,则执行补偿事务撤销已经完成的步骤。(Microsoft Learn)

Microservices.io 对 Saga 的定义也一致:Saga 是一系列本地事务,每个本地事务更新数据库并发布消息或事件触发下一个本地事务;如果某个本地事务因为业务规则失败,则执行一系列补偿事务撤销之前已完成的变更。(microservices.io)

在电商下单场景中,Saga 可以表现为:

text
创建订单成功
→ 扣减积分成功
→ 预扣库存失败
→ 触发补偿:退回积分
→ 触发补偿:取消订单

Saga 的优点是适合长流程、跨系统、异步化和人工介入场景;缺点是每个参与服务都需要提供明确的补偿动作,并且补偿不是数据库回滚,而是业务语义上的反向操作。例如“退积分”不是撤销 SQL,而是新增一笔积分返还流水。

6.2 TCC 模式:Try、Confirm、Cancel 三阶段业务预留

TCC 将一个业务动作拆分为 Try、Confirm、Cancel 三个阶段。Try 阶段预留资源,Confirm 阶段确认提交,Cancel 阶段释放资源。与 Saga 相比,TCC 对业务接口侵入更强,但资源语义更明确,适合账户余额冻结、库存冻结、额度占用等需要先预留再确认的场景。

以支付账户扣款为例:

text
Try:冻结账户余额 100 元
Confirm:将冻结金额转为实际扣款
Cancel:释放冻结金额

Seata 官方站点将 TCC 作为其支持的事务模式之一,并说明 Seata 支持 TCC 模式,且可与 AT 模式混合以获得更高灵活性;同时其功能列表也将 Saga 描述为长事务的有效解决方案。(Seata)

TCC 的核心优势是不会长时间持有数据库层面的全局事务锁,而是通过业务资源冻结实现可控的中间状态。其代价是业务方必须实现三套接口,并处理空回滚、幂等、悬挂、超时取消和状态机一致性等问题。


7. 当前微服务治理下的事务分层模型

现代微服务事务治理可以被抽象为三层:

text
       /\
      /  \      1. 顶层:柔性分布式事务
     /    \        Saga / TCC / Seata
    /      \       适用于金融、支付、账户、库存等核心链路
   /________\
  /          \   2. 中层:消息驱动最终一致性
 /            \     本地消息表 / Transactional Outbox / 最大努力通知
/______________\    适用于大部分跨服务异步解耦场景

底层基石:领域边界、本地事务、幂等、防重、状态机、对账
目标:优先消灭分布式事务需求,而不是默认引入全局事务

这一分层可以解释为什么传统 2PC/XA 在微服务中不再适合作为默认解法:它位于强一致性顶层,却被早期实践错误地套用到大量本可以通过边界重构、消息异步、幂等重试和对账补偿解决的问题上。


8. 工程选型原则

从工程治理角度,跨服务一致性方案可以按以下顺序判断:

第一,能否通过领域重构把强一致约束放回单服务本地事务。如果可以,应优先调整服务边界或聚合边界。

第二,是否只是单边资源并发控制。如果是,应优先使用本地事务、唯一约束、幂等键、状态机和必要的分布式锁,而不是引入全局事务。

第三,是否允许异步最终一致。如果允许,应优先使用 Transactional Outbox、本地消息表、可靠消息、消费者幂等、重试和补偿。

第四,是否涉及资产、履约或用户权益,且必须提供确定的业务恢复路径。如果是,应选择 Saga 或 TCC,并为每个步骤设计状态机、补偿动作、幂等机制、超时处理和对账系统。

第五,是否必须使用 XA/2PC。如果使用,应确认数据库、事务管理器、参与者恢复、prepared transaction 清理、监控告警、超时策略和人工修复 SOP 全部具备。否则,XA/2PC 的一致性收益会被运行时复杂度抵消。


9. 结论

传统分布式事务没有消失,但它不再是微服务一致性治理的默认中心。XA/2PC 通过全局协调提供跨资源原子提交能力,但该能力依赖所有参与者在全局事务边界内共同准备、共同提交或共同回滚。该模型与微服务的自治、数据库私有、故障隔离和独立扩展目标存在结构性张力。

现代微服务治理的主线是:先通过 DDD 和服务边界设计减少跨服务强一致需求,再用本地事务、幂等、防重、消息表、Transactional Outbox、对账和人工兜底覆盖大部分业务场景;只有在金融、支付、库存、账户等核心链路中,才使用 Saga 或 TCC 等柔性分布式事务模式。

因此,“逃离传统分布式事务”的实质不是放弃一致性,而是从数据库层面的强一致提交,转向业务层面的可恢复一致性、可观测一致性和最终一致性治理。对于微服务系统而言,这是一种从“技术事务”到“业务事务”的架构转变。


参考资料

  1. MySQL Reference Manual:XA Transactions。(MySQL开发者专区)
  2. PostgreSQL Documentation:Two-Phase Transactions / PREPARE TRANSACTION。(PostgreSQL)
  3. PostgreSQL Documentation:Prepared transaction 使用建议。(PostgreSQL)
  4. Microsoft Azure Architecture Center:Saga Design Pattern。(Microsoft Learn)
  5. Microsoft Azure Architecture Center:Microservices data considerations / API idempotency。(Microsoft Learn)
  6. Microsoft .NET Microservices Architecture:Data sovereignty per microservice。(Microsoft Learn)
  7. AWS Prescriptive Guidance:Transactional Outbox Pattern。(AWS 文档)
  8. Redis Documentation:Distributed Locks with Redis。(Redis)
  9. Apache Seata Documentation:AT、TCC、Saga、XA transaction models。(Seata)
  10. Microservices.io:Database per Service / Saga Pattern。(microservices.io)
GitHub Discussions

参与讨论

评论会同步到 stellhub/stell-web 仓库的 GitHub Discussions。

Powered by VitePress and GitHub Discussions.