事务大家都很熟悉,小范围来说就是数据库为了保证数据的一致性而做的操作规范和限制。
常见的就是AICD四大特性:原子性,隔离性,一致性,持久性
分布式事务顾名思义就是分布式系统当中的事务如何保证这些特性。
分布式事务分为两块来理解:
1.分布式:那么就会涉及到多个数据库(支持事务),内存和磁盘数据等硬件都不在一起,想从操作系统层面控制是不可能了。那么只能找出一个协调者来组织本地事务一起工作。
2.事务:必须本地数据库支持(无论关系型数据库还是非关系型数据库)
分布式系统有一个很著名的CAP理论,
C 一致性:all nodes see the same data at the same time
所以节点在相同时间看到的数据是相同的,这个可以看作是强一致性,而不是最终一致性。
A 可用性:reads and writes always succeed 服务一直可用,而且是在有效时间内。下图是针对可用性的一些标准
P 分区容错性:the system continues to operate despite arbitrary message loss or failure of part of the system
分布式系统在遇到节点或者网络分区故障的时候,仍然可以提供一致性和可用性的服务。
很好的一篇文章介绍cap的
https://blog.csdn.net/w372426096/article/details/80437198
根据cap原理可以知道,不可能cap全部保证的。所以引出了base理论。
base理论 :ba(基本可用) s(软状态) e(最终一致性)
ba:是牺牲了高可用性,部分机器出现故障,进行服务降级或者限流等措施。
s:一般是指数据有多个副本,允许副本之间的同步有一个较长的时间。
e:最终一致性是指多个数据副本最终会保证数据一致。
经过以上对分布式系统的cap和base理论的理解,可以得知分布式事务只能保证最终一致性。
常见的分布式事务解决方案都不能脱离这两个理论。
分布式事务一些大神也给出了一些理论知识
两阶段提交2pc:是一个强一致性,中心化的原子提交协议。
在这个协议里面有两个角色 一个协调者和多个参与者
两个阶段 分别是投票(预提交)阶段和提交(执行)阶段
存在的问题
性能问题/同步阻塞
无论是第一阶段还是第二阶段,所以参与者和协调者资源都是被锁定的状态,这个过程比较慢的话,会影响整个系统的性能。
单点故障/数据不一致
一旦协调者在某个阶段出现故障,参与者将处与一直阻塞的状态,尤其第二阶段则参与者处以资源锁定状态。
2pc出现单点问题的三种情况
协调者正常,参与者宕机
参与者中的一个或者几个宕机就无法给协议者反馈,那么进入超时机制,一旦参与者在指定时间内会没有反馈,协调者就发送终止事务请求。
协调者宕机,参与者正常
一旦协调者宕机,无论处于哪个阶段,所以参与者将都会阻塞。需要进入协调者备份,且记录操作日志。检测一段时间还没有恢复,则进行激活备份机器,查看操作日志,重新发起请求。
协调者宕机,参与者也宕机
此种情况又可以分为三种情况
发生在第一阶段
因为发生在第一阶段,从参与者选择一个作为协调者,重新发起第一阶段和第二阶段接可以了。
发生在第二阶段且挂了的参与者没有收到commit提交请求
选出新的协调者重新执行第一阶段和第二阶段
发生在第二阶段且挂了的参与者收到了commit提交请求
此时会出现数据不一致的现象部分提交了,部分没有提交,此种情况2pc是无法解决.
三阶段提交3pc:是对两阶段2pc提交的一个改进版本。
主要是针对阻塞/性能问题进行了改进,2pc存在的问题是当协调者故障的时候,参与者会一直阻塞直到协调者恢复。
主要改动点
1.引入超时机制,无论是参与者还是协调者都引入。
2.加入一个准备阶段,在第一阶段和第二阶段之间。以此保证在最后的提交阶段所有节点都能够保持一致。
主要分为3个阶段
cancommit
协调者发起是否可以进行提交的请求,参与者本地获取锁,成功返回消息给协调者
precommit
协调者在收到可以进行预提交消息之后,进行预提交
docommit
真正的执行阶段,进行提交或者回滚
XA理论
- XA是由X/Open组织提出的分布式事务的规范。 XA规范主要定义了 (全局)事务管理器™ 和 (局部)资源管理器(RM) 之间的接口。主流的关系型数据库产品都是实现了XA接口的。
- XA接口是双向的系统接口,在事务管理器 ™ 以及一个或多个资源管理器(RM) 之 间形成通信桥梁。
- 是一套跨语言的标准
XA事务的处理模型
xa的流程
XA的2阶段提交 2PC
来一个xa实战
环境jdk1.8 idea估计 springboot项目
pom.xml配置
org.springframework.boot
spring-boot-starter-web
<!-- db相关配置开始-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<!--db相关配置结束 -->
<dep