分布式事务
分布式事务
- 运行在分布式系统中的事务,是由多个不同的机器上的事务组合而成的
- 只有分布式系统中所有事务执行了才能是成功,否则失败
事务的基本特征ACID
原子性(Atomicity)
- 一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做
一致性
- 指事务执行前和执行后,数据是完整的
隔离性
- 一个事务的执行不能被其他事务干扰
- 一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
持久性
- 也称为永久性,一个事务一旦提交,它对数据库中数据的改变就应该是永久性的保存下来了
分布式事务的目标:解决多个独立事务一致性的问题
分布式事务:一个功能,横跨多个微服务,由于每个微服务不在一个库,没法用数据库事务来保证事务
分布式事务解决方案
二阶段提交协议
基于XA协议的,采取强一致性,遵从ACID
2PC:(2阶段提交协议),是基于XA/JTA规范
XA
- XA是由X/Open组织提出的分布式事务的架构(或者叫协议)
- XA架构主要定义了(全局)事务管理器(Transaction Manager)和(局部)资源管理器(Resource Manager)之间的接口
- XA接口是双向的系统接口,在事务管理器(Transaction Manager)以及一个或多个资源管理器(Resource Manager)之间形成通信桥梁
- 在基于XA的一个事务中,我们可以针对多个资源进行事务管理,例如一个系统访问多个数据库,或即访问数据库、又访问像消息中间件这样的资源
- 这样我们就能够实现在多个数据库和消息中间件直接实现全部提交、或全部取消的事务
- XA规范不是java的规范,而是一种通用的规范
JTA
JTA(Java Transaction API),是J2EE的编程接口规范,它是XA协议的JAVA实现
它主要定义了:
- 一个事务管理器的接口javax.transaction.TransactionManager,定义了有关事务的开始、提交、撤回等操作
- 一个满足XA规范的资源定义接口javax.transaction.xa.XAResource
- 一种资源如果要支持JTA事务,就需要让它的资源实现该XAResource接口,并实现该接口定义的两阶段提交相关的接口
二阶段提交协议
请求阶段(commit-request phase,或称表决阶段,voting phase)
- 在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进入表决过程
- 在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)
提交阶段(commit phase)
- 在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消
- 当且仅当所有的参与者同意提交事务协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务
- 参与者在接收到协调者发来的消息后将执行响应的操作
分布式事务缺点
单点故障
事务的发起、提交还是取消,均由老大协调者管理的,如果协调者宕机故障就会一直存在
同步阻塞缺点
参与分布式系统中的结点在没收到老大的真正提交还是取消事务指令的时候,就是锁定当前的资源,并不真正的做些事务相关操作,所以,整个分布式系统环境就是阻塞的
数据不一致缺点
在老大协调者向小弟们发送真正提交事务的时候,部分网路故障,造成部分系统没收到真正的指令,那么就会出现部分提交部分没提交,因此,这就会导致数据的不一致
无法解决的问题
- 当协调者出错,同时参与者也出错时,两阶段无法保证事务执行的完整性
- 考虑协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了
- 即使有了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交
三阶段提交协议
采取强一致性,遵从ACID
在二阶段上增加了:超时和预提交机制
有这三个主阶段,canCommit、preCommit、doCommit这三个阶段
三阶段提交协议
CanCommit阶段
- 3PC的CanCommit阶段其实和2PC的准备阶段很像
- 协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应
PreCommit阶段
- Coordinator根据Cohort的反应情况来决定是否可以继续事务的PreCommit操作
根据响应情况,有以下两种可能
假如Coordinator从所有的Cohort获得的反馈都是Yes响应,那么就会进行事务的预执行
- 发送预提交请求,Coordinator向Cohort发送PreCommit请求,并进入Prepared阶段
- 事务预提交,Cohort(一群大兵)接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中
- 响应反馈,如果Cohort成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令
假如有任何一个Cohort向Coordinator发送了No响应,或者等待超时之后,Coordinator都没有接到Cohort的响应,那么就中断事务
- 发送中断请求,Coordinator向所有Cohort发送abort请求
- 中断事务,Cohort收到来自Coordinator的abort请求之后(或超时之后,仍未收到Cohort的请求),执行事务的中断
DoCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况:
执行提交
- 发送提交请求,Coordinator接收到Cohort发送的ACK响应,那么他将从预提交状态进入到提交状态,并向所有Cohort发送doCommit请求
- 事务提交,Cohort接收到doCommit请求之后,执行正式的事务提交,并在完成事务提交之后释放所有事务资源
- 响应反馈,事务提交完之后,向Coordinator发送ACK响应
- 完成事务,Coordinator接收到所有Cohort的ACK响应之后,完成事务
缺点
- 如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作
- 而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性
2和3的区别
加了询问,增大成功概率
- 对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)
- 协调者挂了,参与者等待超时后,默认提交事务,有一丢进步
- 如果参与者异常了,协调者也异常了,会造成其他参与者提交
- 在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段
- PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的
基于消息的最终一致性形式
采取最终一致性,遵从BASE理论。
BASE:全称是,Basically Avaliable(基本可用),Soft state(软状态),Eventually consistent(最终一致性)三个短语的缩写
- Basically Avaliable:就是在分布式系统环境中,允许牺牲掉部分不影响主流程的功能的不可用,将其降级以确保核心服务的正常可用
- Soft state:就是指在事务中,我们允许系统存在中间状态,且并不影响我们这个系统,就拿数据库的主从复制来说,是完全允许复制的时候有延时的发生的
- Eventually consistent:还是以数据库主从复制为例说,虽然主从复制有小延迟,但是很快数据就最终一致了
分布式事务不可能100%解决,只能提高成功概率,两阶段之间时间,毫秒级别
补救措施
- 定时任务补偿
- 程序或脚本补偿
- 人工介入
TCC
解决方案:TCC(Try、Confirm、Cancel),两阶段补偿型方案
从名字可以看出,实现一个事务,需要定义三个API:预先占有资源,确认提交实际操作资源,取消占有=回滚
如果后两个环节执行一半失败了,记录日志,补偿处理,通知人工
2PC与TCC
2PC:是资源层面的分布式事务,一直会持有资源的锁
如果跨十几个库,一下锁这么多数据库,会导致,极度浪费资源,降低了吞吐量
TCC:在业务层面的分布式事务,最终一致性,不会一直持有锁,将锁的粒度变小,每操作完一个库,就释放了锁
都是相对的:如果每天只有一个请求,用2PC 比 TCC 要性能高
因为tcc多了次接口调用,而此时的2PC不怕占用资源,反正就一个调用
高并发场景下TCC优势要大
消息中间件实现
seata框架
https://seata.io/zh-cn/docs/overview/what-is-seata.html
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案
睁开眼,书在面前 闭上眼,书在心里