Version: Next
分布式事务问题
引例
- 单体应用被拆分为微服务应用,原来的三个模块被拆分为三个独立应用,分别使用三个独立的数据源
- 业务操作需要调用三个服务来完成
- 每个服务内部的数据一致性由本地事务保证
- 但全局数据一致性无法保证,三个服务物理上分离,逻辑上应当是一个整体
- 仓储服务:针对给定的商品扣除仓储数目
- 订单服务:根据采购需求创建订单
- 账户服务:从用户账户中扣除余额
常见分布式事务解决方案
- 2PC
- TCC
- 可靠消息最终一致性
- 最大努力通知
分布式事务两阶段提交方案
2PC 协议
- 即 两阶段提交协议,将整个事务流程分为两个阶段
- 准备阶段 Prepare Phase
- 提交阶段 Commit Phase
2
指两个阶段P
指准备阶段C
指提交阶段
- 主要由 事务管理器
TM
、事务参与者RM
完成- 常见关系型数据库 Oracle、MySQL 都支持 2PC 协议
准备阶段
事务管理器给每个参与者发送
Prepare
消息,每个数据库参与者都在本地执行事务,并写本地的Undo / Redo
日志,此时事务没有提交
Undo
日志是记录修改前的数据,用于数据库回滚Redo
日志是记录修改后的数据,用于提交事务后写入数据文件提交阶段
如果事务管理器收到了参与者的执行失败或者超时消息,直接给每个参与者发送 回滚
Rollback
消息;否则发送 提交Commit
消息
- 事务参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源
- 必须在最后阶段释放锁
成功情况
失败情况
2PC 解决方案
XA 方案
关系型数据库如 Oracle
、MySQL
都支持 2PC 协议,XA
就是基于数据库层面实现的 2PC 解决方案
- 国际开放标准组织 Open Group 定义了分布式事务处理模型
DTP (Distributed Transaction Prcessing Reference Model)
场景:注册用户送积分
执行过程
- 应用程序
AP
持有用户库
和积分库
两个数据源- 应用程序
AP
通过事务管理器 TM
通知用户库资源管理器 RM
新增用户,同时通知积分库RM
为该新用户新增积分,RM
此时并为提交事务,此时用户和积分资源被锁定事务管理器 TM
收到执行回复,只要一方失败则分别向其他RM
发起事务回滚,回滚完毕,资源锁释放事务管理器 TM
收到执行回复,全部成功,此时向所有RM
发起提交事务,提交完毕,资源锁释放
DTP 模型定义如下角色
AP
(Application Program):即 应用程序,可以理解为使用DTP
分布式事务的程序RM
(Resource Manager):即 资源管理器,可以理解为事务参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务TM
(Transaction Manager):即 事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM
。全局事务 是指分布式事务处理环境中,需要操作多个数据库共同完成的一个工作,这个工作即是一个全局事务- DTP 模型定义
TM
、RM
之间通讯的接口规范叫做XA
,简单理解成数据库提供的 2PC 接口协议,基于数据库的 XA 协议来实现 2PC 又称为XA 方案
三角色交互方式
TM
向AP
提供 应用程序编程接口,AP
通过TM
提交及回滚事务TM
通过XA
接口来通知RM
数据库事务开始、结束、提交、回滚等
XA 方案的缺陷
- 需要数据库层面支持 XA 协议,一般需要是关系型数据库
- 在正式提交前,会锁定相关资源,资源锁需要等到两个阶段结束才释放,性能较差
Seata 方案
传统 2PC 存在的问题在 Seata 中得到了解决,它通过对本地关系型数据库分支事务的协调来驱动完成全局事务,是工作在应用层的中间件
- 性能较好,不会长时间占用连接资源
- 以高效并且对业务零入侵的方式解决微服务场景下面临的分布式事务问题
- 目前提供
AT(即 2PC)
模式及TCC
模式的分布式事务解决方案
Seata 设计思想
- 将一个分布式事务理解成一个 包含了若干
分支事务
的全局事务
- 全局事务的职责是协调其下管辖的分支事务达成一致,要么一起成功提交,要么一起失败回滚
- 通常分支事务就是一个关系型数据库的本地事务
Seata 三组件
- Seata 定义了
3
个组件来协调分布式事务的处理过程
Transaction Coordinator TC
:事务协调器,它是独立的中间件,需要独立部署运行,它维护事务的运行状态,接收TM
指令发起全局事务的提交和回滚,负责与RM
通信协调各个分支事务的提交和回滚Transaction Manager TM
:事务管理器,TM
需要嵌入应用程序工作,它负责开启一个全局事务,并最终向TC
发起全局提交或全局回滚指令Resource Manager RM
:控制分支事务,负责分支注册、状态汇报,并接收事务协调器 TC 的指令,驱动(本地)事务的提交和回滚
Seata 实现 2PC 与传统 2PC 实现的差别:
- 架构层次方面:
- 传统 2PC 方案:
RM
实际上在数据库层面,RM 本质上就是数据库自身,通过 XA 协议实现- Seata:RM 是以
Jar
包形式作为中间件部署在应用程序一侧- 两阶段提交方面:
- 传统 2PC 方案:无论第二阶段的决议是
提交
还是回滚
,事务性资源的锁都要保持到第二阶段结束才能释放- Seata:在第一阶段就提交本地事务,可以省去第二阶段持有锁的时间,提高整体效率
Seata 概述
- Simple Extensible Autonomous Transaction Architecture 简单可扩展自治事务框架
- Transaction ID XID —— 全局唯一事务 ID
3
组件:- Transaction Coordinator
TC
事务协调器:维护全局和分支事务的状态,驱动全局事务提交或回滚。 - Transaction Manage
TM
事务管理器:定义全局事务的范围:开始全局事务、提交或回滚全局事务。 - Resource Manager
RM
资源管理器:管理分支事务处理的资源,与TC
交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
- Transaction Coordinator
TM
向TC
申请开启一个全局事务,全局事务创建成功并生成一个全局唯一事务 ID——XID
XID
在微服务调用链路的上下文中传播RM
(数据库)向TC
注册分支事务,本地分支事务执行并提交,分支事务纳入XID
对应全局事务管辖范围- 各分支事务提交完毕
RM
(数据库)向TC
泛起针对XID
的全局提交或回滚决议TC
调度XID
下管辖的全部分支事务完成提交或回滚请求
Seata 下载安装
- 本次采用
seata-server 0.9.0
版本,官网下载 - 下载后解压,进入
/conf
目录,修改file.conf
配置文件- 修改 自定义事务组名称 + 事务日志存储模式为
db
+ 数据库连接信息 - service 模块、store 模块
- service 模块
- store 模块
- 修改一下组名
service {#vgroup->rgroupvgroup_mapping.my_test_tx_group = "bsx_group" # 修改一下这个名字即可#only support single nodedefault.grouplist = "127.0.0.1:8091"#degrade current not supportenableDegrade = false#disabledisable = false#unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanentmax.commit.retry.timeout = "-1"max.rollback.retry.timeout = "-1"}
- 修改 自定义事务组名称 + 事务日志存储模式为
- 在 MySQL 5.7 中新建
seata
库 - 在
seata
库里建表,脚本在/conf/db_store.sql
- 修改
/conf
目录下的registry.conf
配置文件- 修改为
nacos
registry {# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa# type = "file"type = "nacos" # 修改为 nacosnacos {serverAddr = "localhost:8848"namespace = ""cluster = "default"}# 省略之后的东西 - 修改为
- 启动
Nacos8848
- 启动
seata-server
sh seata-server.sh
- 查看
Nacos
,出现了一个服务,查看详情可以看到其运行在8091
端口,即seata-server