『』分布式事务如何实现?深入解读 Seata 的 XA 模式( 四 )

  • 执行阶段(E xecute):
    • XA start/XA end/XA prepare + SQL + 注册分支
  • 完成阶段(F inish):
    • XA commit/XA rollback
2. 数据源代理
XA 模式需要 XAConnection 。
获取 XAConnection 两种方式:
  • 方式一:要求开发者配置 XADataSource
  • 方式二:根据开发者的普通 DataSource 来创建
第一种方式 , 给开发者增加了认知负担 , 需要为 XA 模式专门去学习和使用 XA 数据源 , 与 透明化 XA 编程模型的设计目标相违背 。
第二种方式 , 对开发者比较友好 , 和 AT 模式使用一样 , 开发者完全不必关心 XA 层面的任何问题 , 保持本地编程模型即可 。
我们优先设计实现第二种方式:数据源代理根据普通数据源中获取的普通 JDBC 连接创建出相应的 XAConnection 。
类比 AT 模式的数据源代理机制 , 如下:
『』分布式事务如何实现?深入解读 Seata 的 XA 模式
本文插图
但是 , 第二种方法有局限:无法保证兼容的正确性 。
实际上 , 这种方法是在做数据库驱动程序要做的事情 。 不同的厂商、不同版本的数据库驱动实现机制是厂商私有的 , 我们只能保证在充分测试过的驱动程序上是正确的 , 开发者使用的驱动程序版本差异很可能造成机制的失效 。
这点在 Oracle 上体现非常明显 。 参见 Druid issue:https://github.com/alibaba/druid/issues/3707
综合考虑 , XA 模式的数据源代理设计需要同时支持第一种方式:基于 XA 数据源进行代理 。
类比 AT 模式的数据源代理机制 , 如下:
『』分布式事务如何实现?深入解读 Seata 的 XA 模式
本文插图
3. 分支注册
XA start 需要 Xid 参数 。
这个 Xid 需要和 Seata 全局事务的 XID 和 BranchId 关联起来 , 以便由 TC 驱动 XA 分支的提交或回滚 。
目前 Seata 的 BranchId 是在分支注册过程 , 由 TC 统一生成的 , 所以 XA 模式分支注册的时机需要在 XA start 之前 。
将来一个可能的优化方向:
把分支注册尽量延后 。 类似 AT 模式在本地事务提交之前才注册分支 , 避免分支执行失败情况下 , 没有意义的分支注册 。
这个优化方向需要 BranchId 生成机制的变化来配合 。 BranchId 不通过分支注册过程生成 , 而是生成后再带着 BranchId 去注册分支 。
4. 小结
这里只通过几个重要的核心设计 , 说明 XA 模式的基本工作机制 。
此外 , 还有包括连接保持、异常处理等重要方面 , 有兴趣可以从项目代码中进一步了解 。
以后会陆续写出来和大家交流 。
3.1.3 演进规划
XA 模式总体的演进规划如下:
  1. 第 1 步(已经完成):首个版本(1.2.0) , 把 XA 模式原型机制跑通 。 确保只增加 , 不修改 , 不给其他模式引入的新问题 。
  2. 第 2 步(计划 5 月完成):与 AT 模式必要的融合、重构 。
  3. 第 3 步(计划 7 月完成):完善异常处理机制 , 进行上生产所必需的打磨 。
  4. 第 4 步(计划 8 月完成):性能优化 。
  5. 第 5 步(计划 2020 年内完成):结合 Seata 项目正在进行的面向云原生的 Transaction Mesh 设计 , 打造云原生能力 。
3.2 XA 模式的使用
从编程模型上 , XA 模式与 AT 模式保持完全一致 。
可以参考 Seata 官网的样例:seata-xa
样例场景是 Seata 经典的 , 涉及库存、订单、账户 3 个微服务的商品订购业务 。
在样例中 , 上层编程模型与 AT 模式完全相同 。 只需要修改数据源代理 , 即可实现 XA 模式与 AT 模式之间的切换 。