# 分布式事务
国际开放标准组织 Open Group 定义了 DTP(Distributed Transaction Processing)规范,在规范中描述了全局的事务管理器和局部的资源管理器之间的接口。该规范的目的是允许多个资源(如数据库,应用服务器,消息队列等)在同一事务中进行访问,这样可以使事务的 ACID 属性跨越应用程序而有效。该规范使用两阶段提交(Two-Phase Commit)来保证所有资源同时提交或者回滚。
回顾一下事务的 ACID 特性:
- 原子性(Atomicity):整个事务中的所有操作,要么都成功,要么都失败,不可能部分操作成功部份操作失败。
- 一致性(Consistency):事务必须使数据库的数据从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作以及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability):在事务完成以后,该事务对数据库做的更改应该持久的保存在数据库中。
而为什么需要分布式事务呢?主要有两种情况:
- 数据库分库分表:在单库单表场景下,当业务数据量达到单库单表的极限时,就需要考虑分库分表,将之前的单库单表拆分成多库多表。分库分表之后,原来在单个数据库上的事务操作,可能就变成跨多个数据库的操作,此时就需要使用分布式事务。
- 业务微服务化:比如互联网金融网站SOA拆分,分离出交易系统、账务系统、清算系统等,交易系统负责交易管理和记录交易明细,账务系统负责维护用户余额,所有的业务操作都以服务的方式对外发布。一笔金融交易操作需要同时记录交易明细和完成用户余额的转账,此时需要分别调用交易系统的交易明细服务和账务系统的用户余额服务,这种跨应用、跨服务的操作需要使用分布式事务才能保证金融数据的一致性。
# 柔性事务
单数据库事务完全遵循 ACID 规范,因此属于刚性事务。而分布式事务要想遵循 ACID 规范比较困难,所以属于柔性事务,满足 BASE 理论。
BASE 理论:BA(Basic Available 业务基本可用性)、S(Soft State 柔性状态)、E(Eventual Consistency 最终一致性)。
柔性事务对 ACID 的支持情况:
- 原子性:严格遵循
- 一致性:事务完成后的一致性严格遵循,事务中的一致性可适当放宽
- 隔离性:并行事务间不可影响。事务中间结果可见性允许安全放宽
- 持久性:严格遵循。
为了可用性和性能的需要,柔性事务降低了一致性(C)和隔离性(I)的要求,即 基本可用,最终一致。
柔性事务的分类:两阶段型、补偿型、异步确保型、最大努力通知型
- 两阶段型:就是分布式事务两阶段提交,对应技术上的 XA、JTA/JTS,这是分布式事务下事务处理的典型模式
- 补偿型(TCC,Try/Confirm/Cancel)。TCC 的思路是尽早释放锁。在 Try 成功的情况下,如果事务要回滚,Cancel 将作为一个补偿机制,回滚 Try 操作。TCC 各操作事务本地化,且尽早提交(放弃两阶段约束)。当全剧事务要求回滚时,通过另外一个本地事务实现“补偿”行为。TCC 是将资源层的两阶段提交转换到业务层,成为业务模型中的一部分。Saga:一阶段直接提交,如果需要回滚,提供一个二阶段补偿接口。AT(FMT):将数据库的提交分为两阶段,一阶段解析 SQL,记录快照,如果需要回滚,在二阶段将快照恢复。
- 异步确保型:将一些同步阻塞的操作变成异步的操作,避免对数据库事务的争用,例如消息事务机制。
- 最大努力通知型:通过通知服务器(消息通知)进行,允许失败,有补偿机制。
# 两阶段提交(Two-phase commit)
两阶段提交协议是由图灵奖得主 Jim Gray 提出的
两阶段提交协议(2PC)把分布式事务分为两个阶段,一个是准备(Prepare)阶段,一个是提交(Commit)阶段。流程如下:
- 准备阶段:协调者向所有参与者发起指令,询问参与者是否准备好进行commit。
- 如果参与者评估指令能够完成,就锁定资源,写好操作日志,然后返回 VOTE-COMMIT 信息给协调者。
- 如果参与者评估指令不能完成,就向协调者发送 VOTE-ABORT 指令,然后自己直接中止事务。
- 提交阶段:如果每个参与者都返回了 VOTE-COMMIT 指令,则协调者向所有参与者发起 GLOBAL-COMMIT指令;如果有任何一个参与者返回了 VOTE-ABORT 指令或者超时未发送,则协调者向所有参与者发送 GLOBAL-ABORT 指令。
- 参与者收到 GLOBAL-COMMIT 指令后,会提交本地事务,释放资源。
- 参与者收到 GLOBAL-ABORT 指令后,会在本地回滚事务。
该协议具体如下图所示

两阶段提交协议在准备阶段时,参与者会锁定资源,一直等待直到协调者发来 GLOBAL-SUBMIT 或 GLOBAL-ABORT 命令。这是一个重量级的操作,能保证强一致性,但是实现起来比较复杂,成本较高,有个很大的问题是会引起阻塞(blocking)。尤其是当参与者在等待协调者的 COMMIT 或 ABORT 指令时,如果协调者挂掉,那么参与者会一直阻塞,直到协调者恢复。
为了解决阻塞问题,有一些其他的分布式事务算法被提出,例如 三阶段提交协议,PAXOS,TCC 等。
未完待续。。。
← CAP定理