Git Theory
Table of contents
分布式事务解决方案
一、分布式事务
事务,就是一组共生共死操作,要么全部成功要么全部失败。
1、本地事务
一般理解的本地事务是指关系型数据库来控制事务,利用数据库本身的事务特性实现。本地事务也叫数据库事务,而传统的单体应用数据库和应用都是一起的,也会称呼为本地事务。本地事务只是一种相对于分布式事务的叫法。
一般事务四大特征:
- A (Atomic):事务原子性。
- C (Consistency) 一致性。修改之后整体上的一致性,如转换A给B转账,A账户扣款100元,B账户添加100元,操作完成之后,二者整理上是一致的。如果A账户扣款,B账户不增加100元或,A账户没扣,但B账户加了100元,整体上就不一致了。
- I (Isolation) 隔离性。主要是并发环境之间的隔离,事务之间不会相互影响。
- D (Durability):持久性。事务完成之后,操作的改变是永久的,不会回滚。
2、分布式事务
分布式系统把一个应用系统拆分为可以独立部署的多个子服务,子服务之间需要通过网络进行远程协作才能完成事务操作就称为分布式事务。
比如电商系统中,下单支付减库存(此处只是举例)。订单系统、支付系统、库存系统三个服务之间相互协作完成一套完整的下单操作。
单体应用本地事务:
begin transaction
// 1、本地操作创建订单
// 2、本地操作发起支付
// 3、本地操作扣减库存
commit transaction
分布式系统的分布式事务:
begin transaction
// 1、本地订单系统 操作创建订单
// 2、调用远程 支付系统发起支付
// 3、调用远程 库存系统扣减库存
commit transaction
在分布式事务中,如果远程支付系统支付成功之后超时,本地订单回滚,那么实际就存在问题。
3、分布式事务场景
(1)微服务架构中。
微服务之间远程调用,典型的跨进程调用组成分布式事务。
(2)单体系统多数据库实例。
单个应用访问多个数据库,需要两个数据库连接,两个连接组成一个分布式事务。
(3)多个服务单个数据库。
虽然是同一个数据库,但是服务之间会跨进程调用,组成一个分布式事务。
二、基本理论
1、CAP理论
CAP 是Consistency、 Availability、 Partition tolerance 三个词的简写。
- C :表示一致性;
- A :表示可用性;
- P :表示分区容忍。
Consistency
一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意节点读取到的数据都是最新的状态。
一致性实现思路:
(1)写入数据库主节点后要将数据同步到其他从节点数据库。
(2)写入数据库主节点后,在数据同步到从节点期间要将从节点数据库锁定,等到同步完成之后再释放锁,以免在新数据写入主节点成功后,向从节点查询到旧的数据。
分布式系统一致性的特征:
(1)写入数据时,需要保证数据同步,因此写操作比较耗时。
(2)保证数据一致性会对资源进行加锁,等到资源一致再释放锁。
(3)请求数据同步失败的从节点会返回错误信息,不能返回旧数据。
Availability
可用性是指任何事物操作都可以得到响应结果,且不会出现响应超时和响应错误。
可用性实现思路:
(1)写入数据库主节点后要将数据同步到其他从节点数据库。
(2)为了保持数据库的可用性,不能将数据库中的资源进行锁定。
(3)如果数据同步操作没有完成,从节点数据库也要返回查询数据,允许返回旧的数据或其他默认信息,但不能返回错误或响应超时。
分布式系统可用性的特征:
- 所有的请求必须要有响应且不回出现响应超时或错误。
Partition tolerance
分区容忍性是指分布式系统的各个节点部署在不同的子网(网络分区),不可避免的出现由于网络问题而导致节点之间通讯失败,但是要求此时节点仍可对外提供服务。
分区容忍性实现思路:
(1)使用异步调用取代同步调用,节点之间尽量松耦合。
(2)添加数据库从节点,节点宕机时由其他节点提供服务。
分布式分区容忍性特征:
- 分区容忍性是分布式系统基本能力。不能因为某个节点宕机,整体服务不可用。
CAP组合理论
在所有的分布式场景中,不会同时具备CAP三个特效,因为在具备了P的前提下C和A是不能共存的。
(1)AP组合。表示放弃一致性,追求可用性和容忍分区容忍。大部分分布式系统设计的选择。
(2)CP组合。表示放弃可用性,追求一致性和忍分区容忍性。 zookeeper就是追求强一致,如跨行转账业务。
(3)CA组合。表示不进行分区,不考虑节点宕机,实现一致和可用性,则非标准的分布式系统。
小结:
分布式系统最多只能同时满足三项中的两项。
较多系统是保证可用性,放弃一致性的AP组合。
2、BASE 理论
CAP的三选二理论中,较多选择AP理论。但是有些场景需要一致性。
BASE理论是Basically Available(基本可用)、Soft state(软状态) 和 Eventually consistent (最终一致性)的缩写,BASE理论是对CAP中AP组合的扩展。通过牺牲强一致性来获取可用性。当某些节点出现故障时,核心服务要保证可用,允许数据在一段时间内不一致,但保证最终达到一致状态。满足BASE理论的事务称为柔性事务。
- 基本可用。表示允许部分功能不可用,核心功能必须可用。
- 软状态。BASE理论允许一些操作中间软状态进行过渡,操作完成后更新真实状态。
- 最终一致。经过一段时间后,所有节点数据达到一致。特点,需要一定时间的延迟等待。
三、解决方案
常见的分布式事务解决方案:
- 2PC 两阶段提交
- TCC
- 可靠消息最终一致性
- 最大努力通知
注意:解决方案只是一种思路和理念。
1、两阶段提交 2PC
2PC
,称为两阶段提交,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(Commit phase)。
2PC中的P指的是准备阶段,C指的是提交阶段。
关系数据库Oracle 和 MySQL支持两阶段提交。
(1)准备阶段(Prepare phase):事务管理器给每个参与者发生Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。Undo 日志是记录修改前的数据,用于数据回滚,Redo 日志是记录修改后的数据,用于提交事务后写入数据文件。
(2)提交阶段(Commit phase):如果事务管理器收到了参与者的执行失败或超时消息时,直接给每个参与者发送回滚Rollback
消息;否组发送提交Commit
消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源(最后阶段释放锁)。
1.1 XA 方案
2PC传统方案是在数据层面实现的,如MySQL/Oracle都支持2PC协议,为了统一标记减少对接成本,国际开放标准组织OpenGroup制定了标准化的处理模型/接口标准,这个分布式事务处理模型叫DTP 。
DTP :Distributed Transaction Processing Reference Model 。
DTP 模型定义了一些事务相关角色:
- AP(Application Program):应用程序,使用DTP分布式事务的程序。
- RM(Resource Manager):资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理对该数据库进行控制,资源管理器控制着分支事务。
- TM(Transaction Manager):事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务的生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成某个业务工作,这个业务工作就是一个全局事务。
在DTP模型中,定义TM和RM之间的通讯接口的规范叫XA,数据库提供2PC协议,是就基于XA协议来实现2PC的,所以2PC也成为XA方案。
DTP模型角色交互:
(1)TM
对AP
提供了应用程序编程接口,AP
通过TM
提交或回滚事务。
(2)TM
交易中间件通过XA
接口来通知RM
数据库事务的开始/结束以及提交/回滚。
小结:
整个2PC的事务流程涉及三个角色AP、TM、RM。AP是2PC分布式事务应用程序;TM是事务管理器,控制整个的全局事务;RM是资源管理器,负责控制分支事务。
基本步骤小结:
(1)在准备阶段,RM执行实际的业务操作,但不提交事务,并且锁定资源;
(2)在提交阶段,TM会接受RM在准备阶段的执行回复,只要有任意一个RM执行失败,TM会通知所有的RM执行回滚操作,否则就通知所有的RM提交该事务。提交阶段结束再释放资源的锁。
XA方案缺点:
- 要求数据库需要支持XA协议。
- 资源所资源等待两个阶段结束之后才释放。
1.2 Seate方案
阿里中间件Seata,开源的分布式事务框架,是基于2PC的基础上进行演进的,解决2PC方案面临的问题。
Seate默认支持AT模式,以及TCC、SAGA 和 XA 等。
Seata 设计是对业务无入侵,解决2PC资源锁的问题。
Seata 把一个分布式事务理解成一个包含了多个分支事务的全局事务。全局事务负责协调下面的各个分支事务达成一致,全部成功或出现失败全部回滚。分支事务值关系数据库的本地事务。
TC(Transaction Coordinator):事务协调器 是独立的中间件,需要独立部署运行,维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各个分支事务的提交或回滚。
TM(Transaction Manager):事务管理器,TM需要嵌入应用程序中工作,负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令。
RM(Resource Manager):资源管理器,控制分支事务,状态汇报,并接收事务协调器TC的指令,驱动分支事务的提交或回滚。
分布式事务处理过程:
(1)TM事务管理器 向 TC 事务协调器 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID;
(2)XID 在微服务调用链路的上下文中传播;
(3)RM资源管理器 向 TC事务协调器注册分支事务,将其纳入XID对应全局事务的管辖;
(4)TM事务管理器 向 TC事务协调器 发起针对XID的全局提交或回滚的决议;
(5)TC事务协调器 调度XID 下管辖的全部分支事务完成提交或回滚请求。
Seate方案实例
优缺点:
优势:seata AT模式改进了XA方案的不足,对业务0入侵。开源者支持,有alibaba系列的生态圈支持。
不足:依赖数据库对XA协议支持,依赖外部的事务协调器组件,seata 版本演进还不够完全成熟,有bug就有风险。
2、TCC
TCC是Try、Confirm、Cancel三个词缩写。
TCC是要求分支事务实现三个操作,分别是预处理Try、确认Confirm、撤销Cancel。Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的操作即回滚操作。
TCC分为三个阶段:
(1)Try 阶段是做业务检查及资源预留,此阶段仅是一个初步操作,它和后续的Confirm一起才能真正构成一个完整的业务逻辑。
(2)Confirm 阶段是做确认提交,Try 阶段的分忧分支事务执行成功后开始执行Confirm。通常情况下,采用TCC则认为Confirm阶段是不会错误的,即只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需要引入重试机制或人工处理。
(3)Cancel 阶段是在业务执行出错需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,采用TCC则认为Cancel解决也是一定会成功的。若Cancel阶段真的出错了,需引入重试机制或人工处理。
TM 事务管理器,可以实现为独立的服务,也可以让全局事务发起方充当TM角色,TM独立出来可以作为公共组件,进行复用。
TM 在发起全局事务时,生成全局事务记录,全局事务ID贯穿整个分布式事务调用链路,用来记录事务上下文,追踪和记录状态,由于Confirm和Cancel失败需要进行重试,因为需要实现幂等,幂等性是指同一个操作无论请求多少次,结果都相同。
TCC解决方案有:
-
seata 支持tcc模式
- tcc-transaction
- Hmily
- ByteTCC
- EasyTransction
2.1 Hmily 实现TCC事务
Hmily 轻量级分布式事务TCC开源框架。支持Dubbo,Spring Cloud等RPC框架进行分布式事务。
官方的定位是金融级柔性分布式事务解决方案。
官网:https://dromara.org
Git仓库:https://github.com/dromara/hmily
主要特征:
- 高可靠性 :支持分布式场景下,事务异常回滚,超时异常恢复,防止事务悬挂
- 易用性 :提供零侵入性式的
Spring-Boot
,Spring-Namespace
快速与业务系统集成 - 高性能 :去中心化设计,与业务系统完全融合,天然支持集群部署
- 可观测性 :Metrics多项指标性能监控,以及admin管理后台UI展示
- 多种RPC : 支持
Dubbo
,SpringCloud
,Motan
,Sofa-rpc
,brpc
,tars
等知名RPC框架 - 日志存储 : 支持
mysql
,oracle
,mongodb
,redis
,zookeeper
等方式 - 复杂场景 : 支持RPC嵌套调用事务
主要实现思路:
Hmily 利用AOP对参与分布式的本地方法与远程方法进行拦截,通过多方拦截,事务参与者能透明的调用到另一方的Try
、Confirm
、Cancel
方法;传递上下文并记录事务日志,酌情进行补偿、重试等操作。
Hmily 没有事务协调器TC角色,事务不依赖数据库XA协议标准,但是需要一个数据库来进行日志存储。
如:mysql/redis/mongodb/zookeeper等。
Hmily 实现的TCC服务预普通的服务一样,只需要暴露一个接口,也就是它的try操作。Confirm/Cancel
操作只是在全局事务提交或回滚需要才提供,因此Confirm/Cancel
操作需要被Hmily的TCC事务框架发现,不需要被调用它的业务服务感知。
TCC 三种异常处理:
- 空回滚
在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法,Cancel 方法需要识别出这是一个空回滚,然后直接返回成功。
出现原因是因为当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候还没来得及执行Try阶段,当故障恢复后,分布式事务进行回滚则会调用二阶段的Cancel方法,从而形成空回滚。
解决思路是关键就是要识别出这个空回滚。思路很简单就是需要判断一阶段是否执行,如果执行了,那就是正常回滚;如果没执行,那就是空回滚。
TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条。再额外增加一张分支事务记录表,其中有全局事务 ID 和分支事务 ID,第一阶段 Try 方法里会插入一条记录,表示一阶段执行了。Cancel 接口里读取该记录,如果该记录存在,则正常回滚;如果该记录不存在,则是空回滚。
- 幂等
为了保证TCC二阶段提交重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、Confirm 和 Cancel 接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据不一致等严重问题。
解决思路在上述“分支事务记录”中增加执行状态,每次执行前都查询该状态。
- 悬挂
悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行。
出现原因是在 RPC 调用分支事务try时,先注册分支事务,再执行RPC调用,如果此时 RPC 调用的网络发生拥堵,通常 RPC 调用是有超时时间的,RPC 超时以后,TM就会通知RM回滚该分布式事务,可能回滚完成后,RPC 请求才到达参与者真正执行,而一个 Try 方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况,我们就称为悬挂,即业务资源预留后没法继续处理。
解决思路是如果二阶段执行完成,那一阶段就不能再继续执行。在执行一阶段事务时判断在该全局事务下,“分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。
优缺点:
优势:Hmily 不依赖数据库协议,没有事务协调器组件,使用需要自己实现接口,实现操作灵活度高。
不足:使用复杂度较高,不保证数据隔离,需要自己预防空回滚、幂等、悬挂现象,相对小众。
配合Spring Cloud相关文档:SpringCloud搭配文档