在微服务,分布式项目为主流架构的现在,分布式事务是一个不得不谈的技术点,本文将作者理解到的分布式事务进行记录.
1:事务是什么?
我之前的博客有事务的介绍, 本文就不介绍基础知识了. mysql进阶之路:mysql中的事务相关知识https://blog.csdn.net/wang5701071/article/details/123815090?spm=1001.2014.3001.5502
java中的事务及使用https://blog.csdn.net/wang5701071/article/details/108663948?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165148083816782246454118%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165148083816782246454118&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-108663948.nonecase&utm_term=%E4%BA%8B%E5%8A%A1&spm=1018.2226.3001.4450
2:本地事务与分布式事务
本地事务:由于之前的项目都是单体项目,也就是每个项目都是独立的一个JVM,所以我们日常使用的事务都只能在本项目中进行acid的操作.也被称为本地事务.
分布式事务:分布式系统是由多个独立的JVM项目通过网络远程调用进行通信.而每个JVM发生错误信息进行回滚的时候,调用链上的所有项目都需要对该操作进行回滚. 多个项目同时进行acid的操作也被称为分布式事务.
3:分布式事务的特性
由于分布式事务是本地事务的升级版,所以本地事务的acid特性,分布式都要满足,来保证向下兼容.
在基于acid的基础上,分布式还需要满足CAP理论.
3.1:CAP理论
CAP
是
Consistency
、
Availability
、
Partition tolerance三个词语的缩写,分别表示一致性、可用性、分区容忍性。但所有分布式事务场景中不会同时具备
CAP
三个特性,因为在具备了
P
的前提下
C
和
A
是不能共存的.所以目前的分布式事务解决方案要么是ap,要么是cp.但目前随着目前的项目越来越多,C强一致性会导致速度会非常慢,
所以目前主流是保证AP,舍弃强一致性,通过其他手段保证最终一致性.
C - Consistency:
一致性是指写操作后的读操作可以读取到最新的数据状态,当数据分布在多个节点上,从任意结点读取到的数据都
是最新的状态。
分布式系统一致性的特点:
1
、由于存在数据同步的过程,写操作的响应会有一定的延迟。
2
、为了保证数据一致性会对资源暂时锁定,待数据同步完成释放锁定资源。
3
、如果请求数据同步失败的结点则会返回错误信息,一定不会返回旧数据。
A - Availability :可用性是指任何事务操作都可以得到响应结果,且不会出现响应超时或响应错误。
P - Partition tolerance :
通常分布式系统的各各结点部署在不同的子网,这就是网络分区,不可避免的会出现由于网络问题而导致结点之间
通信失败,此时仍可对外提供服务,这叫分区容忍性。
3.2:CAP的两种组合方式
AP:
放弃一致性,追求分区容忍性和可用性。这是目前主流的分布式系统的选择。这个放弃一致性是放弃强一致性,而用其他补偿机制来达到最终一致性, 最终一致性就是指数据不是最新的,只需要在一定时间内数据变成最新即可.
业务场景
比如:充值送积分,充值成功后,积分延迟到账,只要用户可以接受在一定时间内到账即可.
CP:
放弃可用性,追求一致性和分区容错性,我们的
zookeeper
其实就是追求的强一致,又比如跨行转账,一次转账请
求要等待双方银行系统都完成整个事务才算完成。
4:BASE理论
BASE
是
Basically Available(
基本可用
)
、
Soft state(
软状态
)
和
Eventually consistent (
最终一致性
)
三个短语的缩 写。BASE
理论是对
CAP
中
AP
的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证 核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE
理论的事务,我们称之为
“
柔
性事务
”
。
Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。如,电商网站交易付款出 现问题了,商品依然可以正常浏览。
Soft state(
软状态
):由于不要求强一致性,所以
BASE
允许系统中存在中间状态(也叫
软状态
),这个状态不影响系统可用 性,如订单的"
支付中
"
、
“
数据同步中
”
等状态,待数据最终一致后状态改为
“
成功
”
状态。
Eventually consistent (最终一致性):最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。
5:解决方案之2PC(两阶段提交)
2PC即两阶段提交协议,
是将整个事务流程分为两个阶段,准备阶段(
Prepare phase
)、提交阶段(
commit phase),
2
是指两个阶段,
P
是指准备阶段,
C
是指提交阶段。
场景举例: 充值送积分, 项目A 进行充值操作,B进行增加积分操作. C监控AB完成情况
第一阶段:
A本地充值成功,B本地增加成功. // A或者B其中一方失败
执行实际的业务操作,但不提交事务,资源锁定;
第二阶段: C看到AB可以成功,通知AB提交事务 // C看到一方失败.通知AB一起回滚.
提交阶段结束资源锁释放。
整个过程由事务管理器和参与者组成,C就是事务管理器,A、B就是事务参与者,事务管理器负责决策整个分布式事务的提交和回滚,事务参与者负责自己本地事务的提交和回滚。
MySql支持的2PC协议:
1.
准备阶段(
Prepare phase
):事务管理器给每个参与者发送
Prepare
消息,每个数据库参与者在本地执行事 务,并写本地的Undo/Redo
日志,此时事务没有提交。 (Undo
日志是记录修改前的数据,用于数据库回滚,
Redo
日志是记录修改后的数据,用于提交事务后写入数
据文件)
2.
提交阶段(
commit phase
):如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者 发送回滚(Rollback)
消息;否则,发送提交
(Commit)
消息;参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:
必须在最后阶段释放锁资源。
6:解决方案之Seata方案
Seata
是由阿里中间件团队发起的开源项目,
它是一个是开源的分布式事务框架。 传统2PC
的问题在
Seata
中得到了解决,它通过对本地关系数据库的分支事务的协调来驱动完成全局事务,是工作在应用层的中间件。主要优点是性能较好,且不长时间占用连接资源,它以高效并且对业务0
侵入的方式解决微服务场景下面临的分布式事务问题,它目前提供
2PC
及
TCC
模式的分布式事务解决方案。
6.1:Seata的设计思想:
Seata的设计目标是对业务无侵入,
Seata
把一个分布式事务理解成一个包含了若干
分支事务
的
全局事务
。全局事务的职责是协调其下管辖的分支事务
达成一致,要么一起成功提交,要么一起失败回滚。
6.2:Seata中存在的角色:
Transaction Coordinator (TC)
: 事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运 行状态,接收TM指令发起全局事务的提交与回滚,负责与
RM
通信协调各各分支事务的提交或回滚。
Transaction Manager (TM)
: 事务管理器,TM
需要嵌入应用程序中工作,它负责开启一个全局事务,并最终 向TC
发起全局提交或全局回滚的指令。
Resource Manager (RM)
: 控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC
的指令,驱动分 支(本地)事务的提交和回滚。
6.3:Seata的执行流程:
- 用户服务的 TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID。
- 用户服务的 RM 向 TC 注册 分支事务,该分支事务在用户服务执行新增用户逻辑,并将其纳入 XID 对应全局 事务的管辖。
- 用户服务执行分支事务,向用户表插入一条记录。
- 逻辑执行到远程调用积分服务时(XID 在微服务调用链路的上下文中传播)。积分服务的RM 向 TC 注册分支事务,该分支事务执行增加积分的逻辑,并将其纳入 XID 对应全局事务的管辖。
- 积分服务执行分支事务,向积分记录表插入一条记录,执行完毕后,返回用户服务。
- 用户服务分支事务执行完毕。
- TM 向 TC 发起针对 XID 的全局提交或回滚决议。
- TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
7:Seata实现2PC与传统2PC的差别:
7.1: 架构层次方面,
传统
2PC
方案的
RM
实际上是在数据库层,
RM
本质上就是数据库自身,通过
XA
协议实现,而 Seata的
RM
是以
jar
包的形式作为中间件层部署在应用程序这一侧的。
7.2: 两阶段提交方面,
传统
2PC
无论第二阶段的决议是
commit
还是
rollback
,事务性资源的锁都要保持到
Phase2
完成 才释放。而Seata
的做法是在
Phase1
就将本地事务提交,这样就可以省去
Phase2
持锁的时间,整体提高效率。