概要
针对分布式数据库,如何保证分布式事务的强一致性,是分布式数据库的关键。分布式事务的强一致性方案这里介绍两种,一种是GTM(global transaction manager),另一种是基于XA协议的两阶段提交(2PC)。注意,本文是基于MySQL数据库的分析,但是思想是数据库通用的。
GTM
全局事务管理器,思想是将原本集中式数据库的MVCC方案拓展到分布式。
要素:
- GXID:全局唯一递增的事务id。
- Global Snapshot: 全局事务快照,我个人理解为一个全局版的ReadView。
流程:
如图所示:
- 分布式事务开启,gate向GTM申请GXID和Global Snapshot,
- 各shard, 开启单机事务,把GXID和Snapshot下发执行。
- 各shard读取数据时, 会结合GXID和Snapshot来读取全局一致的数据。
- 分布式事务提交或者回滚完成之后,Gate向GTM汇报事务状态,使得GTM可以维护所有的全局事务的状态
基于GTM的MySQL分布式事务强一致性方案:
- Global Snapshot(全局快照)
- global_up_limit_id: 当前未提交的全局事务的最小值
- global_low_limit_id:当前已分配的全局事务号+1;(ReadView中 也成为max_id)
- global_trx_ids:当前未提交全局事务id列表
- 基于Global Snapshot的可见性判断
- gxid < global_up_limit_id,对于当前global snapshot都是可见的。
- gxid >= global_low_limit_id,对于当前global snapshot都是不可见的。
- global_trx_ids 中的事务对于当前global snapshot是不可见的
- 数据的读取过程
- 从最新版本开始,找到第一个对于当前global snapshot都可见的数据版本
- 总结:和单机版的MySQL的MVCC版本控制思想一致,不过是将范围扩大到了全局。
- 局限性:
- 存在性能瓶颈,无法支撑大规模集群。
- 扩展性查,无法满足副本的全局一致性读以及备份和恢复需求。
XA
MySQL的XA协议是一个事务协议,用于实现分布式事务。XA协议包含了两个阶段:prepare和commit。在prepare阶段,事务协调者(Transaction Coordinator)在所有参与者(Participants)上执行prepare操作。如果所有参与者都成功的执行了prepare操作,那么该事务就可以被提交(commit)。如果有一个参与者在prepare阶段失败,则该事务将被回滚。
在MySQL中,XA协议通常用于在多个MySQL实例之间执行分布式事务。通过实现XA协议,多个MySQL实例可以参与到同一个分布式事务中,并保证事务的ACID特性。
在MySQL中,XA协议需要开启事务支持(transaction support),以及使用XID(transaction identifier)来跟踪事务。
两阶段提交(2PC)
第一阶段:
1. 协调者向参与者发出执行请求执行事务的消息
2. 参与者执行事务, 并将undo 和 redo 信息记录在事务日志中,但不commit, 资源已经被锁定。
3. 参与者向协调者发送投票消息,Agree表示事务执行成功,Abort表示执行失败。
第二阶段:
1. 协调者收到所有参与者的投票信息,所有参与者都返回Agreee,协调者向所有参与者发送commit消息。
2. 参与者收到 ‘commit’消息后,执行提交操作,并释放在第一阶段中申请的资源。
3. 如果任何一个参与者返回“否决”消息,协调者将向所有参与者发送“回滚”
4. 参与者收到“回滚”消息,执行回滚操作,并释放第一阶段中申请的所有资源。
总结:
1. 相较于GTM, XA和2PC的实现很复杂,但是可以支持大规模集群,扩展性也很好,可以实现副本的全局一致性读以及全局一致性的备份和恢复。
2. 但是XA和2PC对资源的要求比较高,因为第一阶段会锁定资源,造成资源的紧张。