1. 分布式事务问题本质
1.1 为什么单体事务在微服务中失效
在传统的单体应用架构中,事务管理相对简单直接。所有业务逻辑和数据库访问都在同一个进程内完成,数据库连接也是单一的。当我们执行一个包含多个SQL操作的事务时,数据库的事务管理器可以轻松保证ACID特性。一次简单的COMMIT命令就能确保所有操作要么全部成功,要么全部回滚。
然而在微服务架构下,情况变得复杂得多。一个业务操作往往需要跨多个服务协作完成,每个服务都有自己的独立数据库实例。这种架构带来了几个关键挑战:
- 跨服务调用:一个业务操作需要通过网络调用多个服务,这些调用可能成功也可能失败
- 多数据库实例:每个服务操作的是不同的数据库,无法通过单一数据库事务来保证一致性
- 网络不可靠:服务间的网络通信可能出现延迟、超时甚至完全失败
这种情况下,传统的本地事务机制就完全失效了。我们无法保证跨服务的多个数据库操作能够作为一个原子单元执行。典型的表现就是"部分成功"问题 - 某些服务的操作成功了,而其他服务失败了,导致系统数据处于不一致状态。
提示:在微服务架构中,CAP理论告诉我们无法同时保证一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)。分布式事务方案通常需要在一致性和可用性之间做出权衡。
1.2 典型数据不一致场景
让我们通过一个具体的例子来说明这个问题。考虑一个电商系统中的创建订单场景:
- 订单服务创建订单记录
- 调用库存服务扣减库存
- 调用账户服务扣减用户余额
如果这三个步骤中的任何一个失败,系统就会处于不一致状态。例如:
- 订单创建成功,但库存扣减失败 → 用户看到了订单但实际库存不足
- 订单和库存都成功,但扣款失败 → 用户获得了商品但未付款
- 网络超时导致重复调用 → 库存被多次扣减
这些问题可以归纳为以下几类:
| 问题类型 | 具体表现 |
|---|---|
| 原子性丢失 | 跨服务的多个操作无法作为一个原子单元执行 |
| 幂等性问题 | 网络重试可能导致某些操作被重复执行 |
| 回滚困难 | 没有全局协调者,难以对所有参与方执行回滚 |
| 脏读/脏写 | 一个事务读取了另一个未提交事务的数据,或覆盖了其他事务的未提交修改 |
这些问题的本质在于,我们需要一个全局事务协调器来管理跨服务的多个本地事务,确保它们要么全部成功,要么全部回滚。这正是Seata这类分布式事务框架要解决的核心问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Seata核心架构模型
2.1 三大角色
Seata的架构设计采用了经典的"三角色"模型,每个角色各司其职:
| 角色名称 | 全称 | 职责描述 |
|---|---|---|
| TC | Transaction Coordinator | 事务协调中心,负责维护全局事务状态,协调分支事务的提交或回滚 |
| TM | Transaction Manager | 定义全局事务边界,负责开启、提交或回滚全局事务 |
| RM | Resource Manager | 管理分支事务资源,向TC注册分支事务,并执行分支事务的提交或回滚操作 |
这种角色分离的设计使得系统职责清晰,扩展性强。TC作为中心节点保持轻量级,而业务相关的TM和RM可以分布式部署。
2.2 事务模型
2.2.1 全局事务
全局事务(Global Transaction)是业务层面的完整事务单元。例如电商系统中的"创建订单"操作可能涉及多个服务的协作,这些操作共同构成一个全局事务。每个全局事务都有一个唯一的XID(Transaction ID),用于在整个分布式系统中标识该事务。
2.2.2 分支事务
分支事务(Branch Transaction)是全局事务的组成部分,对应各个服务中的本地事务。例如在"创建订单"场景中:
- 订单服务的本地事务是一个分支事务
- 库存服务的本地事务是另一个分支事务
- 账户服务的本地事务是第三个分支事务
每个分支事务都有自己的分支ID(Branch ID),并与全局XID关联。
2.3 运行流程
Seata的事务执行流程可以概括为以下几个关键步骤:
- TM向TC申请开始一个全局事务,TC生成全局唯一的XID
- XID通过服务调用链传递到各个参与服务
- 每个RM在执行本地事务前,先向TC注册分支事务
- RM执行本地事务,但不立即提交,而是将执行结果报告给TC
- 当所有分支事务都执行完成后,TM向TC发起全局提交或回滚请求
- TC根据全局事务状态,向所有RM发送提交或回滚指令
- 各RM根据TC的指令完成最终提交或回滚操作
这个流程的核心思想是将多个本地事务组织成一个逻辑上的全局事务,由TC统一协调它们的最终提交或回滚。这种设计既保持了本地事务的ACID特性,又实现了跨服务的分布
