本文是对分布式事务原理、规范的科普,主要围绕两阶段提交协议展开。最后描述了在应用框架层面模拟两阶段提交协议的简化设计。
1 事务/分布式事务
1.1 事务
事务是数据库从一个稳定状态变迁到另一个稳定状态的保证,具备 ACID 这 4 个特性:
- 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态。
- 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性限制没有被破坏。
- 隔离性(Isolation):两个事务的执行是互不干扰的,两个事务时间不会互相影响。
- 持久性(Durability):在事务完成以后,该事务对数据库所作的更改便持久地保存在数据库之中,并且是完全的。
例如应用程序需要更新多条相关数据时就需要进行事务处理。
1.2 分布式事务与 XA 规范
分布式事务是指会涉及到操作多个数据库的事务,同样必须保证 ACID。
其就是将对同一库事务的概念扩大到了对多个库的事务:对同一库的 SQL 操作对应了分布式事务中对一个库的事务。
X/Open XA 定义了分布式事务处理的规范,并由数据库厂商在驱动层面进行实现。XA 规范的基础是两阶段提交协议,并定义了分布式事务处理所涉及的角色:
- 应用程序(AP)
- 事务管理器(TM)
- 资源管理器(RM)
- 通信资源管理器(CRM)
可以这样认为,事务管理器即事务处理中间件(分布式事务处理系统);资源管理器即各个数据库。
2 两阶段提交协议
两阶段提交协议(Two-phase commit protocol, 2PC)将一次分布式事务处理划分为两个阶段:预提交阶段(也称为准备阶段或投票阶段),提交阶段。
2.1 预提交阶段
这是两阶段提交协议的第一个阶段,分布式事务处理系统咨询各个资源管理器是否可以提交本地事务,各个资源管理器会把这个咨询过程写入日志,以便进行回滚或提交。
当一个数据库接收到咨询后,它会将需要执行的操作写入日志,禁止其他写入操作(锁定资源)。
如果分布式事务中某数据库预提交失败或提交失败,那该数据库会根据日志进行自身的操作回滚,并解锁。
2.2 提交阶段
分布式事务处理系统对各个资源管理器下达提交/回滚的指令,使整个分布式事务结束。
当一个数据库接受到提交/回滚指令时,它将根据第一阶段的日志进行提交/回滚处理。
两阶段提交协议可以在数据库层面通过驱动支持,也可以在应用框架中按照其原理进行设计实现。
3 分布式事务应用框架
使用数据库驱动方式实现两阶段事务有两个不足:
- 随着分布式事务的参与者增多,效率会明显降低
- 对应用开发者透明,调试不便
- 必须依赖数据库,不是所有数据库都实现了 XA 规范
3.1 角色
- 发起者:分布式事务发起者,需要提供回查恢复接口。
- 参与者:参与到分布式事务的其他系统,提供提交/回滚接口。这里的提交/回滚接口即是对数据库数据的 SQL 操作。
- 活动管理器:负责管理分布式事务(活动、操作)。
- 定时器:触发对分布式事务活动的捞取,以备回查恢复。
3.2 交互时序
两阶段提交时序:
因为系统在上述交互中不是绝对可靠的,所以需要一定的方式进行事务状态恢复,保证所有参与者最终一致。
回查恢复时序:
3.3 关键点
- 参与者提供的提交/回滚接口必须满足幂等性,即定时触发重复调用提交/回滚时不会重复操作同一资源
- 根据发起者生成 txId,回查恢复时根据 txId 调用发起者回查恢复接口
- 活动管理器与发起者同库/不同库时,事务活动、操作状态变迁的不同处理
- 事务内调用操作的顺序
- 定时任务定时间隔/重试次数