分布式事务笔记(XA,TCC,Saga)
distributed note基础理论
CAP理论
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。这被称为CAP理论,已经被证实。
- 一致性(Consistency) :在分布式系统中所有的数据备份,在同一时刻都保持一致状态,如无法保证状态一致,直接返回错误。
- 可用性(Availability):在集群中一部分节点故障,也能保证客户端访问系统并得到正确响应,允许一定时间内数据状态不一致。
- 分区容错性(Partition tolerance):分布式系统在遇到任何网络分区故障时,仍然能保证对外提供满足一致性和可用性的服务,除非整个网络环境都发生故障。
ACID特性(刚性事务,强一致性)
把多条语句作为一个整体进行操作的功能,称为数据库事务。数据库事务可以确保该事务范围内的所有操作全部成功或者全部失败。
事务具有 4 个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。
- 原子性(Atomicity):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
- 一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
- 事务隔离(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
BASE理论(柔性事务)
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写,BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)
- 基本可用(Basically Available):是指分布式系统在出现不可预知故障的时候,允许损失部分可用性——但请注意,这绝不等价于系统不可用。
- 软状态(Soft state):和硬状态相对,是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
- 最终一致性(Eventually consistent):强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
总的来说,BASE理论面向的是大型高可用可扩展的分布式系统,和传统事务的ACID特性使相反的,它完全不同于ACID的强一致性模型,而是提出通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID特性与BASE理论往往又会结合在一起使用。
分布式方案
XA规范
Open Group组织定义的一套DTP(Distributed Transaction Processing)分布式事务处理模型,主要包含以下四部分:
- AP(应用程序)
- TM(事务管理器):中间件,负责多个事物之间的协调
- RM(资源管理器):数据库等资源
- CRM(通信资源管理器):消息中间件
XA规范包括两套函数,分别以 xa_
和 ax_
开头,使 TM 可以对 RM 进行的操作:
- xa_open,xa_close:建立和关闭与资源管理器的连接;
- xa_start,xa_end:开始和结束一个本地事务;
- xa_prepare,xa_commit,xa_rollback:预提交、提交、回滚一个本地事务;
- xa_recover:回滚一个已进行预提交的事务;
- ax_开头的函数使资源管理器可以动态地在事务管理器中进行注册,并可以对XID(TRANSACTION IDS)进行操作;
- ax_reg,ax_unreg;允许一个资源管理器在一个TMS(TRANSACTION MANAGER SERVER)中动态注册或撤消注册。
基于XA规范衍生出下面的两阶段提交(2PC)、三阶段提交(3PC)。
2PC(两阶段提交)
2PC就是分布式事务中将事务分为两步进行提交,两阶段提交基于ACID理论。
提交流程:
- 准备阶段:预提交,首先两个事务都会去操作自己的数据库,但是这次操作数据库并不会commit,也就是说不生效,只是试探性的看看这次操作能否成功,无论成功与否,如果成功的话将会记录此次的操作记录,并一直锁定要操作的数据资源,返回结果给事务管理器,如果失败则直接回滚所做的操作,并立即释放锁定的数据资源,也将结果返回给事务管理器;
- 提交阶段:交易中间件事务管理器收到所有的事务预操作返回结果,并审查所有数据库返回的预提交结果,如所有数据库都可以提交,交易中间件将要求所有数据库做正式提交,这样该全局事务被提交。而如果有任一数据库预提交返回失败,交易中间件将要求所有其它数据库回滚其操作,这样该全局事务被回滚。
二阶段提交的一些问题:
- 同步阻塞,事务执行过程中所有 RM 都是阻塞型的,第三方访问 RM 占有的资源时会被阻塞。
- 单点故障,TM 一旦发生故障,RM 会被阻塞。尤其在提交阶段,所有 RM 都处于锁定资源状态中,无法完成事务操作;(可以选择新的 TM,但无法解决 RM 被阻塞的问题)。
- 数据不一致,提交阶段 TM 向 RM 发送提交信息,发生局部网络故障,会导致存在 RM 未收到提交信息无法提交事务情况,导致出现数据不一致现象。
3PC(三阶段提交)
相比于2PC,3PC 把 2PC 的准备阶段再次进行拆分,并且 3PC 引入了 RM 超时机制
提交流程:
- 检查阶段:TM 询问 RM,是否具备执行事务的条件,RM 进行自身事务必要条件的检查;
- 预提交阶段:TM 通知 RM 进行事务的预提交;
- 提交阶段:TM 根据预提交阶段 RM 的反馈结果通知 RM 是否进行事务提交或是进行事务回滚;
TCC(事务补偿方案)
Try-Confirm-Cancel,TCC是基于BASE理论
TCC的核心思想就是校验、资源锁定、补偿,对每个操作(Try)都提供确认(Confirm)和取消(cancel)的操作,这样根据操作的结果,来确认是进行 Confirm 还是 Cancel。
XA的两阶段提交是基于资源层面的,而 TCC 也是一种两阶段提交,但它是基于应用层面的。
提交流程:
- Try:主要负责对业务进行数据检查和资源预留,例如:对资金进行
冻结
;对状态更改为处理中
; - Confirm:确认执行业务的操作,例如:进行实际
资金扣除
;更改状态为最终结果
; - Cancel:取消执行业务的操作,例如:
解冻资金
;更改状态为未处理
;
TCC存在的一些问题:
- 业务操作的是不同服务的Try来进行资源预留,每个Try都是独立完成本地事务,因此不会对资源一直加锁。
- 业务服务需要提供try、confirm、cancel,业务侵入性强,如不适用三方框架要做到对各阶段状态的感知,比较麻烦。
- Confirm/Cancel要做幂等性设计。
常见的微服务系统大部分接口调用是同步的,这时候使用TCC来保证一致性是比较合适的。
Saga(补偿方案,只保证 ACD,I无法保证)
Saga其实是30年前的一篇数据库论文里提到的一个概念。在论文中一个Saga事务就是一个长期运行的事务,这个事务是由多个本地事务所组成, 每个本地事务有相应的执行模块和补偿模块,当saga事务中的任意一个本地事务出错了, 可以通过调用相关事务对应的补偿方法恢复,达到事务的最终一致性。 Saga的核心是补偿,与TCC不同的是Saga不需要Try,而是直接进行 confirm、cancel 操作。
提交流程:
- Confirm:依次按顺序依次执行资源操作,各个资源直接处理本地事务,如无问题,二阶段什么都不用做;
- Cancel:异常情况下需要调用的补偿事务(逆操作)来保证数据的一致性。
Saga对服务的要求:幂等性和补偿可交换原则,因为可能因为网络问题,会导致出现超时重试的情况,这样就需要服务支持幂等性,避免多次请求带来的问题。
重试取消的情况。补偿可交换原则是指Saga并行处理的过程中,如果发生了超时重试事件之后,并进行了补偿的操作,那么补偿操作是直接生效的。为了满足这个要求,需要我们在设计系统的过程中保留所有的事务数据
相较于TCC:
优势:
- 一阶段提交本地事务,无锁,高性能;
- 事件驱动模式,参与者可异步执行,高吞吐;
- 应用成本低,补偿服务易于实现;
劣势:
- 无法保证隔离性(脏写)
Saga的两种实现方式:
集中式:集中式的Saga实现一般是通过一个Saga对象来追踪所有的Saga子任务的调用情况, 根据调用情况来决定是否需要调用对应的补偿方面,协调器和调用方是在一个进程中的。缺点就是耦合度太高。
分布式:分布式的Saga的实现使用过事件驱动的,相关的服务监听相关的事件,从而触发该服务,因此分布式Saga也叫事务编排。分布式的好处是,降低了耦合性以及系统的复杂性,系统的逻辑处理是基于事件。
基于分布式Saga处理的例子,通过 Kafka 作为消息中间件,每个服务订阅相关的Channel,当捕获相关的事件之后就自动触发服务。这里面最重要的是要持久化相关的环节,比如持久化事件信息以及中间信息,因为事务出现回滚或者补偿的时候会需要这些信息。更多访问:https://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation
EOF