通俗易懂分布式事务之2PC、3PC、AT、TCC

单机服务事务提交回滚操作是需要拿到Connection对象,调用提交commit方法或者rollback方法回滚的,例如下面操作

Connection conn = DriverManager.getConnection(...);
try{
con.setAutoCommit(false);
Statement stmt = con.createStatement();
//1 or more queries or updates
con.commit();
}catch(Exception e){
con.rollback();
}finally{
con.close();
}

要想提交或者回滚,必须拥有Connection对象,然而在分布式环境,jvm都是不同的,自然就拿不到其他服务的Connection对象,所以在分布式环境,我们无法保证原子性。因此分布式事务就需要另寻出路。

1. 术语

  • 全局事务:分布式环境,操作涉及很多服务,全局事务能保证这些服务的原子性,要提交就全部服务都会提交,要回滚全部服务都会回滚
  • 分支事务:分支事务建立在全局事务当中,是属于单个服务的事务

2. 2PC

2PC 即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase)

与本地事务的区别就是 会加入一个事务协调者的角色,这个事务协调者控制整体的事务提交

2.1 流程

  1. PreCommit阶段

    事务协调者开启全局事务,参与者向事务协调者注册分支事务,然后走自己的业务代码,在这过程中如果发生了异常参与者会发送信息到事务协调者我异常了,需要全部回滚。如果一切正常,告诉事务协调者我可以提交了,等待事务协调者发送commit指令
  2. Commit阶段

    事务协调者向所有分支事务发送commit指令,释放数据库资源

在这里举个具体的例子

我们有两个服务:订单服务、库存服务

用户需要买东西,首先要创建订单,创建订单前需要去锁定库存,然后再去创建订单。

1. 事务协调者开启全局事务
2. 库存服务开启事务,向事务协调者注册一个分支事务
3. 库存服务锁定库存
4. 订单服务开启事务,向事务协调者注册一个分支事务
5. 订单服务创建订单
6. 事务协调者进行全局提交事务
7. 库存服务提交事务
8. 订单服务提交事务
9. 全局事务完成

在任何一个流程中异常,事务协调者都会发起全局回滚事务,这种方式,在全局事务完成前,Connection对象都不会释放,因为你释放了你就无法控制了,缺点很明显,如果订单服务需要处理很久,库存服务Connection对象都不会释放,一直占用着,这种是强原子性的很浪费资源

2.2 实现2PC

XA协议,是X/Open组织提出的跨异构技术实现2PC的接口标准。

使用XA协议首先前提就是,需要关系型数据库支持,目前主流数据库:

  • MySQL: InnoDB 引擎支持 XA 事务,并实现了 XA 接口。
  • PostgreSQL: 从版本 8.0 开始支持 XA 事务,通过插件接口实现。
  • Oracle: 支持 XA 事务,使用 OracleXADataSource 提供 XA 接口。
  • SQL Server: 支持 XA 事务,使用 MSDTC 提供 XA 接口。
  • DB2: 支持 XA 事务,使用 DB2 Universal JDBC 驱动器提供 XA 接口。
  • Sybase ASE: 支持 XA 事务,使用 JConnect 提供 XA 接口。

2.2.1 MySQL实现流程:

  1. START

第一步开启XA事务

库存DB:

XA START 'xid'
UPDATE product SET num = num - 1 where id = 100
XA END 'xid'

订单DB:

XA START 'xid'
INSERT INTO order values(xxx)
XA END 'xid'
  1. PREPARE

第二步,准备就绪,等待事务协调者同意我提交

库存DB:

XA PREPARE 'xid'

订单DB:

XA PREPARE 'xid'
  1. commit

全部提交

库存DB

XA COMMIT 'xid'

订单DB:

XA COMMIT 'xid'

2.2.3 seata支持XA

XA协议JDK接口定义:javax.sql.XADataSource

seata框架支持XA协议,seataXA模式文档:https://seata.apache.org/zh-cn/docs/v1.6/dev/mode/xa-mode/

seata官方XA模式demo:

https://github.com/apache/incubator-seata-samples/tree/master/xa-sample/springboot-feign-seata-xa

2.3 2PC缺陷

  • 强一致性,每个分支事务得等待所有分支事务都准备好,才能提交释放
  • 协调者发生故障。分支事务会一直阻塞下去。

2. 3PC

三阶段提交协议(3PC)主要是为了解决两阶段提交协议的阻塞问题,2pc存在的问题是当协作者崩溃时,参与者一直阻塞。

与两阶段提交不同的是

  1. 引入超时机制
  2. 在最前面引入CanCommit阶段,为了防止参与者服务不可用,询问各个服务能不能开启事务

2.1 流程:

  1. CanCommit阶段

    事务询问阶段,协调者向参与者发送CanCommit请求,询问是否可以执行事务提交操作。如果有参与者返回NO,就不进行下一步操作了
  2. PreCommit阶段

    进入PreCommit后就和2PC一样了,区别就是有超时机制
  3. Commit阶段

    提交,释放数据库资源,与2PC一样

2.2 缺点

还是要等到全局事务完毕资源才释放,占用资源大

3. Seata AT模式

Seata AT模式文档:https://seata.apache.org/zh-cn/docs/v1.6/dev/mode/at-mode

Seata AT模式的核心是对业务无侵入,是一种改进后的2PC

主要的实现是,在每个服务的数据库中新建一张undo_log表,结构如下:



content: 更改后的内容,

rollback_info: 回滚的内容

每个分支事务执行SQL都会解析SQL,保存content,rollback_info,插入到undo_log表中。如果全局事务通知需要回滚,去通过对比content和解析rollback_info,执行sql达到回滚的效果,如果全局事务通知全局事务成功,异步删除undo_log的记录。

这种方式不需要等待全局事务的提交才提交,能解决2PC、3PC资源占用的问题,实际就是异常就去补偿的思想

3.1 流程

  1. 事务入口会开启全局事务,分支事务注册事务(非入口事务通过传递xid来判断是加入哪个事务)
  2. 分支事务执行SQL之前会解析SQL,生成前置镜像
  3. 解析出SQL如果是更新修改数据这种情况,seata会锁住更新修改的数据,另一个全局事务进来想要更改更新修改的数据就需要等待全局事务结束才能进行更改对应着seata的lock_table表

  4. 执行SQL
  5. 根据SQL生成后置镜像,如果到时候需要回滚,直接执行后置镜像
  6. 插入数据到undo_log表
  7. 提交本地事务
  8. 如果所有分支事务都是正常的,就释放锁,然后异步删除所有的分支事务undo_log的记录
  9. 如果发生异常,所有事务都对前置镜像进行解析,生成SQL,执行回滚操作
  10. 如果发生异常,需要回滚,后置镜像当中的值,不等于当前值,代表有其他业务一样的更改了这行数据,这时候就需要人工去处理了(往往如果设置了数据库字段update_time自动更新时间会很容易导致这个情况出现,不能用数据库的自动更新时间,自动更新时间得去到业务代码实现里)

3.2 缺点

seata AT模式,事务是软状态需要考虑数据最终一致性,性能相对来说不是那么高,得去加锁,得动态去解析SQL插入数据库增加了和数据库的交互

4. Seata TCC模式

Seata TCC模式文档:https://seata.apache.org/zh-cn/docs/v1.6/dev/mode/tcc-mode

TCC 是分布式事务中的二阶段提交协议,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),TCC模式对代码的入侵很大,但它的性能很好,还可以便捷的解决、空回滚、幂等、悬挂问题。

空回滚:没有执行try却执行了cancel。参与者分支注册完成之后会执行参与者一阶段try RPC 方法发送rpc时候网络延迟抖动,事务协调者全局回滚,参与者没有执行try却进入cancel

幂等:多次进入try。执行完二阶段之后,由于网络抖动或者宕机问题,会造成事务协调者收不到参与者执行confirm的返回结果,事务协调者会重复发起调用,直到二阶段执行结果成功

悬挂:执行了cancel又进入try。进入try 方法时,出现网路拥堵,由于 seata 全局事务有超时限制,执行 try 方法超时后,进行全局回滚,回滚完成后如果此时 RPC 请求才到达参与者 ,执行 try 方法进行资源预留,从而造成悬挂。

Seata社区这个博客写的挺好 https://seata.apache.org/zh-cn/blog/seata-tcc/ 解释了seata是怎么样处理解决、空回滚、幂等、悬挂问题。

4.1 流程

假设一个转账需求,A给B转100,一般做法是判断够不够钱,如果够钱A-100,B+100

在TCC模式下把这个需求拆分为 Try-Confirm-Cancel

  1. try 阶段,查询A够不够钱,够的话冻结A 100块钱
  2. confirm阶段,执行业务代码,预先给B + 100
  3. 如果一切正常,执行A-100,B + 100
  4. 如果有异常,执行try的回滚逻辑,A解除冻结的100

4.2 缺点

TCC模式有代码侵入,需要把一个业务拆分为三个方法,事务具有软状态,确认和取消操作都可能出现问题,需要考虑如何处理失败情况以保证最终一致性

通俗易懂分布式事务之2PC、3PC、Seata AT模式、Seata TCC模式的更多相关文章

  1. 分布式事务(1)---2PC和3PC理论

    分布式事务(1)---2PC和3PC理论 分布式事物基本理论:基本遵循CPA理论,采用柔性事物特征,软状态或者最终一致性特点保证分布式事物一致性问题. 分布式事物常见解决方案: 2PC两段提交协议 3 ...

  2. 分布式事务与Seate框架(3)——Seata的AT模式实现原理

    前言 在上两篇博文(分布式事务与Seate框架(1)--分布式事务理论.分布式事务与Seate框架(2)--Seata实践)中已经介绍并实践过Seata AT模式,这里一些例子与概念来自这两篇(特别是 ...

  3. 分布式事务的2PC、3PC和TCC

    1.2PC协议 2PC 是二阶段提交(Two-phase Commit)的缩写,顾名思义,这个协议分两阶段完成.第一个阶段是准备阶段,第二个阶段是提交阶段,准备阶段和提交阶段都是由事务管理器(协调者) ...

  4. 面试被问分布式事务(2PC、3PC、TCC),这样解释没毛病!

    整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...

  5. 分布式事务一2PC

    分布式事务解决方案之2PC(两阶段提交) 前面已经学习了分布式事务的基础理论,以理论为基础,针对不同的分布式场景业界常见的解决方案有2PC.TCC.可靠消息最终一致性.最大努力通知这几种. 3.1.什 ...

  6. 分布式事务概述--2pc的概念

    转载自一个大拿:http://www.cnblogs.com/LBSer/p/4715395.html 前阵子从支付宝转账1万块钱到余额宝,这是日常生活的一件普通小事,但作为互联网研发人员的职业病,我 ...

  7. 分布式事务与Seate框架(2)——Seata实践

    前言 在上一篇博文(分布式事务与Seate框架(1)--分布式事务理论)中了解了足够的分布式事务的理论知识后,到了实践部分,在工作中虽然用到了Seata,但是自己却并没有完全实践过,所以自己私下花点时 ...

  8. 分布式一致性算法 2PC 3PC Paxos

    分布式一致性算法的目的是为了解决分布式系统 一致性算法可以通过共享内存(需要锁)或者消息传递实现,本文讨论后者实现的一致性算法,不仅仅是分布式系统中,凡是多个过程需要达成某种一致的场合都可以使用. 本 ...

  9. 分布式事务之深入理解什么是2PC、3PC及TCC协议?

    导读 在上一篇文章<[分布式事务]基于RocketMQ搭建生产级消息集群?>中给大家介绍了基于RocketMQ如何搭建生产级消息集群.因为本系列文章最终的目的是介绍基于RocketMQ的事 ...

  10. 分布式事务解决方案汇总:2PC、3PC、消息中间件、TCC、状态机+重试+幂等(转)

    数据一致性问题非常多样,下面举一些常见例子.比如在更新数据的时候,先更新了数据库,后更新了缓存,一旦缓存更新失败,此时数据库和缓存数据会不一致.反过来,如果先更新缓存,再更新数据库,一旦缓存更新成功, ...

随机推荐

  1. linux下使用CPAN安装Perl模块

    首先从CPAN网站下载CPAN模块 此处使用wget命令直接在linux下下载: wget https://cpan.metacpan.org/authors/id/A/AN/ANDK/CPAN-2. ...

  2. Solution -「AGC 058D」Yet Another ABC String

    \[\mathfrak{Defining~\LaTeX~macros\dots} \newcommand{\chr}[1]{\underline{\texttt{#1}}} \] \(\mathscr ...

  3. CDS标准视图:设备描述 I_EquipmentText

    视图名称: I_EquipmentText 视图类型:基础视图 视图代码: 点击查看代码 @EndUserText.label: 'Equipment - Text' @ObjectModel.dat ...

  4. w3cschool-Linux 教程

    https://www.w3cschool.cn/linux/ Linux 安装 本章节我们将为大家介绍 Linux 的安装,安装步骤比较繁琐,现在其实云服务器挺普遍的,价格也便宜,如果自己不想搭建, ...

  5. Linux基础:用户与用户组

  6. axios请求拦截器和响应拦截器

    axios里面可以设置拦截器 ,在请求发送之前做一些事情: 拦截器分[请求拦截器]和[响应拦截器] 参考地址:https://www.jb51.net/article/150014.htm 参考的地址 ...

  7. 修改NuGet包默认存放位置

    默认情况下,NuGet下载的包存放在系统盘(C盘中),这样一来,时间长了下载的包越多,C盘占用的空间也就越多. 1.问题描述 默认情况下,NuGet下载的包存放在系统盘(C盘中,一般在路径C:\Use ...

  8. LeetCode 第2题:两数相加

    LeetCode 第2题:两数相加 题目描述 给你两个 非空 的链表,表示两个非负的整数.它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字. 请你将两个数相加,并以相同形式返 ...

  9. RocketMQ实战—6.生产优化及运维方案

    大纲 1.RocketMQ集群如何进行权限机制的控制 2.如何对RocketMQ集群进行消息堆积的追踪 3.如何处理RocketMQ的百万消息积压问题 4.针对RocketMQ集群崩溃的金融级高可用方 ...

  10. Doris BloomFilter原理

    1.Bloom Filter的核心是一个[m]位的bitset和[k]个hash函数. 初始时bitset中所有位的值都设置为0,假设取[m = 10],[k = 3],用蓝色表示某位为0,红色表示为 ...