最早的分布式事务模型是 X/Open 国际联盟提出的 X/Open Distributed Transaction Processing(DTP)模型,也就是大家常说的 X/Open XA 协议,简称 XA 协议
![](https://img.kancloud.cn/f7/fb/f7fba491d045305781a67bc595629a89_347x250.png)
DTP 模型中包含一个全局事务管理器(TM,Transaction Manager)和多个资源管理器(RM,Resource Manager)。全局事务管理器负责管理全局事务状态与参与的资源,协同资源一起提交或回滚;资源管理器则负责具体的资源操作。
XA 协议描述了 TM 与 RM 之间的接口,允许多个资源在同一分布式事务中访问
基于 DTP 模型的分布式事务流程大致如下:
![](https://img.kancloud.cn/41/4a/414ab85344bccb2988d23738a30c31e9_363x414.png)
1.应用程序(AP,Application)向 TM 申请开始一个全局事务。
2.针对要操作的 RM,AP 会先向 TM 注册(TM 负责记录 AP 操作过哪些 RM,即分支事务),TM 通过 XA 接口函数通知相应 RM 开启分布式事务的子事务,接着 AP 就可以对该 RM 管理的资源进行操作。
3.当 AP 对所有 RM 操作完毕后,AP 根据执行情况通知 TM 提交或回滚该全局事务,TM 通过 XA 接口函数通知各 RM 完成操作。TM 会先要求各个 RM 做预提交,所有 RM 返回成功后,再要求各 RM 做正式提交,XA 协议要求,一旦 RM 预提交成功,则后续的正式提交也必须能成功;如果任意一个 RM 预提交失败,则 TM 通知各 RM 回滚。
4.所有 RM 提交或回滚完成后,全局事务结束
** 原子性**
XA 协议使用 2PC(Two Phase Commit,两阶段提交)原子提交协议来保证分布式事务原子性。
两阶段提交是指将提交过程分为两个阶段,即准备阶段(投票阶段)和提交阶段(执行阶段):
![](https://img.kancloud.cn/f1/8a/f18a94abee25798c93fb6a74b1f88a62_362x406.png)
准备阶段:
TM 向每个 RM 发送准备消息。如果 RM 的本地事务操作执行成功,则返回成功;如果 RM 的本地事务操作执行失败,则返回失败。
提交阶段
如果 TM 收到了所有 RM 回复的成功消息,则向每个 RM 发送提交消息;否则发送回滚消息;RM 根据 TM 的指令执行提交或者回滚本地事务操作,释放所有事务处理过程中使用的锁资源
**隔离性**
XA 协议中没有描述如何实现分布式事务的隔离性,但是 XA 协议要求 DTP 模型中的每个 RM 都要实现本地事务,也就是说,基于 XA 协议实现的分布式事务的隔离性是由每个 RM 本地事务的隔离性来保证的,当一个分布式事务的所有子事务都是隔离的,那么这个分布式事务天然的就实现了隔离性。
以 MySQL 来举例,MySQL 使用 2PL(Two-Phase Locking,两阶段锁)机制来控制本地事务的并发,保证隔离性。2PL 与 2PC 类似,也是将锁操作分为加锁和解锁两个阶段,并且保证两个阶段完全不相交。加锁阶段,只加锁,不放锁。解锁阶段,只放锁,不加锁
![](https://img.kancloud.cn/3c/54/3c54cb28d8ce554ea3c86d3afcf80641_358x340.png)
如上图所示,在一个本地事务中,每执行一条更新操作之前,都会先获取对应的锁资源,只有获取锁资源成功才会执行该操作,并且一旦获取了锁资源就会持有该锁资源直到本事务执行结束。
MySQL 通过这种 2PL 机制,可以保证在本地事务执行过程中,其他并发事务不能操作相同资源,从而实现了事务隔离
**一致性**
前面提到一致性有两层语义,一层是确保事务执行结束后,数据库从一个一致状态转变为另一个一致状态。另一层语义是事务执行过程中的中间状态不能被观察到。
前一层语义的实现很简单,通过原子性、隔离性以及 RM 自身一致性的实现就可以保证。至于后一层语义,我们先来看看单个 RM 上的本地事务是怎么实现的。还是以 MySQL 举例,MySQL 通过 MVCC(Multi Version Concurrency Control,多版本并发控制)机制,为每个一致性状态生成快照(Snapshot),每个事务看到的都是各 Snapshot 对应的一致性状态,从而也就保证了本地事务的中间状态不会被观察到。
虽然单个 RM 上实现了 Snapshot,但是在分布式应用架构下,会遇到什么问题呢?
![](https://img.kancloud.cn/e6/3d/e63df9012155c7554310e68d3cbfc4d0_360x199.png)
如上图所示,在 RM1 的本地子事务提交完毕到 RM2 的本地子事务提交完毕之间,只能读到 RM1 上子事务执行的内容,读不到 RM2 上的子事务。也就是说,虽然在单个 RM 上的本地事务是一致的,但是从全局来看,一个全局事务执行过程的中间状态被观察到了,全局一致性就被破坏了。
XA 协议并没有定义怎么实现全局的 Snapshot,像 MySQL 官方文档里就建议使用串行化的隔离级别来保证分布式事务一致性: “As with nondistributed transactions, SERIALIZABLE may be preferred if your applications are sensitive to read phenomena. REPEATABLE READ may not be sufficient for distributed transactions.”(对于分布式事务来说,可重复读隔离级别不足以保证事务一致性,如果你的程序有全局一致性读要求,可以考虑串行化隔离级别.)
当然,由于串行化隔离级别的性能较差,所以很多分布式数据库都自己实现了分布式 MVCC 机制来提供全局的一致性读。一个基本思路是用一个集中式或者逻辑上单调递增的东西来控制生成全局 Snapshot,每个事务或者每条 SQL 执行时都去获取一次,从而实现不同隔离级别下的一致性。比如 Google 的 Spanner 就是用 TrueTime 来控制访问全局 Snapshot
XA 协议是 X/Open 提出的分布式事务处理标准。文中提到的 2PC、3PC、TCC、本地事务表、Seata in AT mode,无论哪一种,本质都是事务协调者协调各个事务参与者的本地事务的进度,使使所有本地事务共同提交或回滚,最终达成一种全局的 ACID 特性。在协调的过程中,协调者需要收集各个本地事务的当前状态,并根据这些状态发出下一阶段的操作指令。这个思想就是 XA 协议的要义,我们可以说这些事务模型遵守或大致遵守了 XA 协议
### 优缺点
XA 协议通常实现在数据库资源层,直接作用于资源管理器上。因此,基于 XA 协议实现的分布式事务产品,无论是分布式数据库,还是分布式事务框架,对业务几乎都没有侵入,就像使用普通数据库一样。
XA 协议严格保障事务 ACID 特性,能够满足所有业务领域的功能需求,但是,这同样是一把双刃剑。
由于隔离性的互斥要求,在事务执行过程中,所有的资源都被锁定,只适用于执行时间确定的短事务。同时,整个事务期间都是独占数据,对于热点数据的并发性能可能会很低,实现了分布式 MVCC 或乐观锁(optimistic locking)以后,性能可能会有所提升。
同时,为了保障一致性,要求所有 RM 同等可信、可靠,要求故障恢复机制可靠、快速,在网络故障隔离的情况下,服务基本不可用
- 概述
- CAP理论
- BASE理论
- ACID
- 分布式系统相关技术
- 主流数据库连接池
- 基础
- 系统单点
- 负载均衡
- HTTP重定向负载均衡
- DNS域名解析负载均衡
- 反向代理负载均衡
- IP负载均衡
- 数据链路层负载均衡
- 负载均衡算法
- 轮询法(Round Robin)
- 加权轮询(Weight Round Robin)
- 随机算法(Random)
- 源地址Hash算法
- 加权随机法(Weight Random)
- 最小连接数法(Least Connections)
- 接入层负载均衡
- 软件架构
- 性能
- 性能测试指标
- 响应时间
- 并发数
- 吞吐量
- 性能计数器
- 性能测试方法
- 性能测试报告
- 性能优化
- Web前端性能优化
- 应用服务器性能优化
- 可用性
- 服务降级
- 伸缩性
- 扩展性
- 事件驱动架构
- 安全性
- 信息加密技术
- 分布式系统概述
- 自动化
- 分布式唯一ID
- 幂等设计
- 分布式锁
- 脑裂
- 一致性原理
- Paxos
- Zab
- Raft
- 分布式远程服务调用
- RMI
- Spring RMI
- WebService
- SOA服务架构
- 微服务架构
- 微服务的九大特性
- 服务注册和发现
- 解决方案及组件
- 分布式网关
- 注册中心
- Zookeeper
- ZNode
- Watch接口
- 持久节点-配置中心实现原理
- 临时节点-注册中心
- Zookeeper选举
- Zookeeper角色
- ZooKeeper工作原理
- 选主流程
- 同步流程
- Leader工作流程
- Follower工作流程
- 常见限流算法
- 计数器算法
- 漏桶算法
- 令牌桶算法
- 滑动窗口
- 计数器&滑动窗口
- 断路器
- 大流量高并发高可用
- 高可用
- 高并发/大流量
- 分布式缓存系统
- 基本概念
- 缓存命中率
- 缓存最大元素
- 缓存回收策略
- 回收算法
- 缓存穿透与缓存雪崩
- CDN缓存
- 缓存分类
- memcached
- 客户端路由原理
- 内存管理机制
- Redis
- Redis数据模型
- redisObject/Redis type/Redis encoding
- 命令的类型检查和多态
- skiplist跳跃表
- 为什么使用跳跃表
- redis-内存管理机制
- Redis淘汰策略
- Redis持久化策略
- Redis并发竞争
- redis主从复制
- Redis集群实现方案
- Redis Cluster
- redis事务
- Redis-Sentinel
- Redis适用场景
- Redis客户端
- redis rehash原理
- dict数据结构
- 触发rehash的条件
- 渐进式rehash
- 渐进式rehash过程
- Redis多线程版本
- 缓存实际应用
- 堆缓存-Guava Cache
- 主要参数
- Caffeine
- Spring注解缓存
- 分布式存储
- Database
- AUTOCOMMIT
- 脏读&幻读&不可重复读
- 子查询
- 连接
- 内连接
- 自连接
- 自然连接
- 外连接
- 组合查询
- 隔离级别
- 数据库范式
- 索引实现机制
- 数据库拆分
- 表分区
- 分库
- 分表
- MySQL
- MySQL基础架构
- 锁分类
- 排它锁&独占锁
- 共享锁
- 间隙锁
- 表级锁
- 存储引擎
- 磁盘IO
- 磁盘结构图
- 磁盘数据读写原理
- MySQL索引原理
- B+树索引
- 局部性原理
- 索引数据结构
- 联合索引
- 最左前缀匹配原则
- 建索引的几大原则
- 数据文件和索引文件
- 执行计划explain
- 常见问题
- 数据页
- MYSQL单表存储量计算
- 回表
- 索引覆盖
- 索引下推
- 页分裂和页合并
- InnoDB
- innodb索引
- Innodb引擎的底层实现
- MyISAM
- MyISAM引擎的底层实现
- MVCC
- Next-Key Locks
- MySQL索引类型
- MYSQL复制
- 主从复制
- 读写分离
- MySQL Dual-Master
- 分库分表实现方案
- MySQL事务实现原理
- MYSQL调优
- 性能优化
- HBase
- 不停机分库分表迁移
- RDBMS&NoSQL
- 分布式事务
- 协议或事务模型
- X/Open XA协议
- 分布式事务编程接口规范JTA
- TCC模型
- 解决方案
- 两阶段提交2PC
- 三阶段提交3PC
- Seata
- 分布式事务Seata产品模块
- AT模式
- TCC模式
- Saga模式
- XA模式
- 基于消息中间件的最终一致性事务方案
- 消息队列
- AMQP
- JMS
- ActiveMQ
- RabbitMQ
- RocketMQ
- RocketMQ基本概念
- 主要特性
- 分区顺序消息
- 全局顺序消息
- 消息可靠性
- 定时消息
- 消息重试
- 死信队列
- 分布式事务消息
- RocketMQ架构
- Producer
- Consumer
- NameServer
- Broker
- RocketMQ设计
- 消息存储
- 页缓存与内存映射
- 消息刷盘
- 通信机制
- console控制台
- RocketMQ部署架构
- Kafka
- Pulsar
- MQ消息重复消费与丢失
- 主流消息队列比较
- 分布式调度系统
- 分布式搜索
- 分布式计算
- 架构案例
- 秒杀业务
- 秒杀整体架构
- 常见的监控系统
- 小米手机抢购秒杀方案
- 架构师领导艺术
- 架构师箴言
- 技术leader核心职责
- WEB服务器
- Servlet
- Servlet实现
- Servlet生命周期
- Servlet容器工作模式
- Servlet工作原理
- servlet线程安全
- CGI&FastCGI
- CGI
- FastCGI
- FastCGI与CGI特点
- CGI与Servlet比较
- HTTP Server
- Nginx
- Apache
- Nginx与Apache比较
- Application Server
- Tomcat
- Tomcat总体架构
- Connector
- 连接器核心功能
- ProtocolHandler
- EndPoint
- Processor
- Adapter
- Container
- 请求定位Servlet的过程
- Lifecycle生命周期
- Tomcat模块设计
- Tomcat实例
- Tomcat运行原理
- spring & servlet
- Tomcat启动流程
- Tomcat支持的I/O模型
- Tomcat应用层协议
- Tomcat类加载机制
- Tomcat类加载器
- Tomcat类加载器层次
- Apache+Tomcat
- 序列化
- XML&JSON
- JSON
- JAVA原生序列化
- hessian
- 常见中间件
- Canal
- Databus
- ELK日志套件
- 数据库连接池
- spring状态机
- 常见解决方案
- 二维码扫码登录原理
- 前沿技术
- Saas服务
- 服务网格(Service Mesh)
- 云原生
- 常见面试问题
- Redis持久化的几种方式
- Redis的缓存失效策略
- 附录
- 二将军问题
- 常见问题定位步骤
- 如何快速熟悉新系统
- 制定技术方案套路
- NUMA陷阱