XA分布式事务

XA基本原理

在分布式数据库(如你正在研究的 TDSQL )中,XA 分布式事务 是保证跨多个节点操作时数据"要么全成功,要么全回滚"的标准方案。它是一种基于强一致性的设计,在金融级场景中应用广泛。

1. 什么是 XA?

XA 是由 X/Open 组织提出的分布式事务处理标准。它定义了三个核心组件之间的交互:

  • 应用程序 (AP):定义事务的边界(开始、提交、回滚)。
  • 资源管理器 (RM):通常指数据库(如 MySQL、Oracle)。它们负责管理实际的数据。
  • 事务管理器 (TM) :也就是协调器。负责统筹全局,协调所有 RM 的状态。

2.核心机制:两阶段提交 (2PC) 的完整流程

在分布式数据库(如 TDSQL)中,2PC 旨在将跨多个分片(Set)的操作封装为一个原子事务。该过程由 事务管理器(TM,如 SQL 引擎) 统一调度,各 资源管理器(RM,如 MySQL+Agent) 协同配合。

第一阶段:准备阶段 (Prepare Phase)

此阶段的目标是"探测"所有参与者是否具备提交事务的能力,并锁定必要资源。

  1. 下发预提议 :TM 向所有参与该事务的 RM 发送 XA PREPARE 指令。
  2. 资源锁定与日志落盘
    • RM 在本地执行 SQL 操作。
    • RM 记录 Redo Log (用于故障恢复)和 Undo Log(用于回滚)。
    • RM 锁定相关的数据库行记录,防止其他事务修改。
  3. 反馈承诺
    • 若执行成功,RM 返回 Ready 状态,并承诺只要 TM 要求提交,它一定能成功。
    • 若因锁冲突或空间不足失败,RM 返回 Fail
第二阶段:提交与确认阶段 (Commit & ACK Phase)

此阶段根据第一阶段的投票结果,执行"全成"或"全败"的最终决策。

  1. 决策逻辑
    • 全局提交 :只有当所有 RM 都反馈 Ready 时,TM 才在日志中标记事务为"已决定提交",并广播 XA COMMIT
    • 全局回滚 :只要有任意一个 RM 反馈 Fail 或超时未响应,TM 广播 XA ROLLBACK
  2. 执行与释放
    • RM 接收到 COMMIT 指令后,正式修改数据状态并释放持有的物理锁。
  3. 确认回执 (ACK)
    • RM 在完成本地提交后,必须向 TM 发送 ACK 确认信号
  4. 事务终结
    • TM 收集到所有 RM 的 ACK 后,认为该分布式事务生命周期彻底结束,从内存中抹除事务状态,并向客户端返回成功。

如何解决丢包与宕机问题

根据不同的阶段和丢包发生的时刻,处理机制有所不同。我们可以分情况来看:

1. 情况一:第一阶段(Prepare)的响应丢包

场景 :SQL 引擎(协调器)发送了 PREPARE,某个 Set 执行成功并返回了 Ready,但这个响应包在网络中丢了。

  • 结果 :SQL 引擎在规定的超时时间内没有收到该 Set 的回复。
  • 处理 :SQL 引擎会认为该节点可能发生了故障或网络中断。为了保证绝对安全,SQL 引擎会向所有 涉及到的 Set 发送 ROLLBACK 指令。
  • 状态:此时所有 Set 都会回滚,事务以失败告终,保证了原子性。

2. 情况二:第二阶段(Commit)的指令丢包

场景 :所有 Set 都返回了 Ready。SQL 引擎发出了 COMMIT 指令,但发往其中一个 Set 的指令包丢了。

  • 结果:其他 Set 成功提交了,但那个丢包的 Set 还傻傻地带着锁在等指令。
  • 处理
    • 重试机制(推模式) :SQL 引擎(作为协调器)会记录事务日志。如果发现某个 Set 没有确认 Commit 成功,它会不断地重试发送 COMMIT 指令,直到该 Set 成功接收并返回确认为止。
    • Agent 的作用(拉模式) :在 TDSQL 架构中,分布在各机器上的 Agent 会发现本地有一个"处于 Prepare 状态但超时的事务",它会去询问 ZooKeeper 或管理节点:"这个事务到底该不该提?" 一旦得到确认为 Commit,Agent 会在本地强制 MySQL 完成提交。

3. 最危险的情况:协调器与参与者同时宕机

如果 SQL 引擎在刚发出第一个 COMMIT 包后就挂了,且接收到包的 Set 也挂了。

  • 问题 :剩下的 Set 处于 Ready 状态,它们不敢私自提交(万一有人失败了呢),也不敢私自回滚(万一协调器已经让别人提交了呢)。这就造成了资源阻塞
  • TDSQL 的解决办法
    • 利用 ZooKeeper :TDSQL 将全局事务的状态记录在强一致性的 ZooKeeper 中。
    • 故障自愈:当新的 SQL 引擎(新协调器)通过选举产生后,它会去 ZooKeeper 读取未完成的事务状态。如果发现事务标记为"已决定提交",它会通知所有 Set 继续执行。

为什么重试要推拉模式结合

之所以"推"和"拉"都要,本质上是为了在性能实时性极端容灾之间取得平衡。

为什么不能只有"推模式"(协调者重试)?

核心问题:无法处理"协调者单点崩溃"。

  • 场景陷阱 :如果 SQL 引擎(协调者)在发出一半 COMMIT 指令后突然宕机,而此时网络又发生了丢包。
  • 后果 :由于协调者已经"死了",没人会再发起重试。那些没收到指令的 Set 会一直保持 PREPARED 状态,死死锁住数据库资源。
  • 结论 :只靠"推",在协调者出故障时,整个集群会陷入长时间的死锁阻塞,直到人工干预。这在金融场景下是不可接受的。
为什么不能只有"拉模式"(Agent 主动询问)?

核心问题:实时性差,且对核心组件压力巨大。

  • 效率低下 :Agent 扫描本地事务并询问 ZooKeeper 通常是定时触发的(比如每 5 秒或 10 秒一次)。如果只靠"拉",每次网络抖动导致的丢包都要等几秒钟才能恢复,这会显著拉低系统的吞吐量。
  • "惊群效应"与性能损耗
    • 如果一个事务涉及 100 个 Set,丢包后这 100 个 Agent 都去疯狂询问 ZooKeeper,会给 ZK 带来巨大的瞬间压力。
    • 频繁轮询本地事务表也会消耗数据库服务器的 CPU 和 IO。
  • 结论:只靠"拉",系统会变得非常"迟钝",且在高并发场景下容易产生不必要的性能瓶颈。

XA 事务的优缺点

优点 缺点
强一致性:最接近单机数据库的体验,不会出现中间状态。 性能损耗高:两次网络往返(RTT),且在整个过程中会长时间占用数据库锁。
业务透明:由底层架构处理,开发者不需要写复杂的补偿逻辑。 同步阻塞:如果 TM 在第二阶段前宕机,参与者会陷入等待,资源无法释放。
行业标准:主流数据库(MySQL, PostgreSQL, Oracle)原生支持。 单点故障:对协调器(TM)的依赖性极强。

相关推荐
笨手笨脚の5 小时前
分布式系统的本质是什么
分布式
czlczl200209256 小时前
Zookeeper
分布式·zookeeper·云原生
布吉岛的石头7 小时前
分库分表实战:Sharding-JDBC 快速落地
分布式·mysql
渔民小镇12 小时前
4 行代码接入 Spring —— ionet 的生态融合之道
java·服务器·分布式·游戏
苍煜13 小时前
Kafka vs RocketMQ 生产环境选型指南
分布式·kafka·rocketmq
m0_7162550014 小时前
第二部分 电商离线数仓 全套项目代码(可直接在你伪分布式 Hive 运行)
hive·hadoop·分布式
旷世奇才李先生14 小时前
Spring Cloud Alibaba 2026微服务全栈实战:服务治理\+流量控制\+分布式事务
分布式·微服务·架构
Amy1870211182314 小时前
虚拟电厂为什么必须“牵手”微电网?答案全在这里
分布式·安全·能源
旷世奇才李先生16 小时前
Redis 7\.0实战:分布式缓存与高可用集群搭建全指南
redis·分布式·缓存