专栏首页我要变牛我还不懂什么是分布式事务

我还不懂什么是分布式事务

老大:来,你搞一搞分布式事务吧 我:......,啥是事务? 我:先从理论学起吧

我不懂什么是事务

如果事务都不懂,就更不用说分布式事务了,于是我马上开始学习了。

事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。

事务应该具有 4 个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特性。

换成比较容易理解的话就是,就是一组操作比如增删改查四个操作要么都成功,要么都失败,不存结果不一致的状态。

我不懂什么是分布式事务

终于弄明白什么是事务了,又来了分布式事务。为什么需要分布式事务呢?

事务更多指的是单机版、单数据库的概念。分布式事务 指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上 。

换成比较容易理解的话,就是多个事务之间再保持事务的特性,也就是多个事务之间保证结果的一致性。

XA规范

有了分布式事务的场景,就会有解决该问题的方式规范,XA规范就是解决分布式事务的规范,具体描述见维基百科解释:

XA规范提供了一种重要思想:

1、引入全局事务的控制节点,事务的协调者 2、多个本地事务划分多阶段提交(也就是下面讲的2PC,3PC)

我不懂分布式方案

有了规范就会有落地方案,下面介绍基于XA规范的几个实现协议。

首先介绍两阶段提交( Two-phase Commit )和三阶段提交( Three-phase Commit )

2PC( Two-phase Commit )

两阶段提交,顾名思义就是要分两步提交。

这里第一阶段称为准备或者投票阶段。引入一个负责协调各个本地资源管理器的事务管理器,

本地资源管理器一般是由数据库实现,事务管理器在第一阶段的时候询问各个资源管理器是否都就绪,并执行完除提交事务外所有事情,然后把结果返回给事务协调者。

如果收到每个资源的回复都是 成功,则在第二阶段提交事务,如果其中任意一个资源的回复是 失败, 则回滚事务。

这里的实现方式和我们平常开黑玩游戏时差不多,当我们组队时,队长会让大家准备,让队员上完厕所吃饱饭,如果所有队员都准备好,那就开始游戏,如果有任一一个队员没有吃饱,没有确认准备好,就不会开始游戏。

但是这种协议也会存在一些问题,如下:

同步阻塞,这是2PC最大的问题, 严格的2PC执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态

解决方案:引入引入超时机制,如果长时间没有收到响应,执行特定的动作。

协调者单点故障,协调者在2PC中是最重要的角色,同时也意味着如果他出问题,整个过程就GG了

解决方案:单点故障的常规方案就引入副本然后当主节点挂掉后,重新选主,就像组队游戏中,如果队员都准备好后,队长长时间蹲厕所不开始游戏,游戏程序一般就会踢掉队长,其他组员切换成队长身份。

数据不一致,虽然解决了上面几个问题,但是由于分布式系统存在很多网络抖动和调用失败场景还是会有数据不一致的情况,下面分为协调者、参与者、网络等故障来详细分析一下:

1、协调者发送准备命令前挂掉

这种相当于事务直接没有开始,没有啥太大影响

2、协调者发送准备命令后挂掉

这种情况,如果参与者没有超时机制,就会造成资源锁定

3、协调者发送提交命令前挂掉

这种情况和上一种情况类似,也会造成资源锁定

4、协调者发送提交命令后挂掉

这种情况很可能是能够成功执行分布式事务的,因为已经到了提交阶段说明其他参与者都已经准备好,如果失败就不断重试

5、协调者发送回滚命令前挂掉

这种情况和2、3是类似的,由于参与者收不到执行操作的命令,如果没有超时会一直阻塞并占据着资源

6、协调者发送回滚命令后挂掉

这种情况和4差不多,也是很大概率是能够成功执行回滚事务的,如果没有成功,由于已经形成了决议,所以只能不断重试

7、协调者发送准备命令后,部分参与者挂掉

这种情况协调者有超时机制,直接判定成失败,然后通知所有参与者回滚

8、协调者发送准备命令后挂掉,且部分参与者挂掉

这种情况重新选举协调者后,发现还在第一阶段,由于没有收到挂掉参与者的响应,所以判定失败,通知其他参与者执行回滚

9、协调者发送提交或回滚命令后挂掉,且收到消息的参与者挂掉

这种情况重新选举协调者后,没有收到消息的参与者没有执行事务,但是协调者无法确定收到消息的参与者执行第二阶段的提交或回滚到底是否成功,就会出现事务不一致的情况

3PC( Three-phase Commit )

从上面介绍的相关内容也可以大体知道2PC的缺点和解决方式,于是就有了下面的解决协议,三阶段提交

从百科可以看到3PC的引入主要就是为了解决上面我们说的2PC的缺点,咋就能解决呢?

1、3PC是非阻塞协议

好的,就是为了解决了资源占用问题,主要也就是引入了参与者超时机制

2、 第一阶段与第二阶段之间插入了一个准备阶段

解决了在两阶段提交中,参与者在投票之后,由于协调者发生崩溃或错误,而导致参与者处于无法知晓是否提交或者回滚的“不确定状态”,也就是为了保证最后提交阶段之前所有参与节点状态一致

3PC 把2PC第一阶段再次拆分为2个阶段,多了一个阶段其实就是在执行事务之前来确认参与者是否正常,防止个别参与者不正常的情况下,其他参与者都执行了事务锁定资源。

他的大概步骤其实可以按照参与者4个状态来划分

0、初始状态,此阶段事务发起者触发全局事务,参与者切换本地状态为开始状态,并把自己注册到协调者中。

1、可提交或状态等待,此阶段协调者发送命令到每个注册过来的参与者,让他们更改状态为可提交状态。

2、预提交状态,此阶段协调者收到参与者确认可以提交并进入状态,然后协调者向他们发送预提交消息,参与者锁定资源,并更改状态为预提交状态。同时 协调者也进入预提交状态。

3、提交状态,此阶段协调者根据参与者预提交的结果执行提交或回滚操作,然后释放资源。

通过这种方式可以解决一些2PC状态不一致问题。JBoss上大佬的总结:

大概意思是,通过引入预提交阶段,协调者能够确定参与者提交前的状态,同时参与者也能够推断其他参与者状态

协调者正常的情况下,可以根据参与者状态切换的结果来决定是执行还是回滚。多出的一个预提交阶段就是为了统一状态。

参与者如果没有收到协调者消息,会默认执行提交,虽然可能会导致数据不一致。

协调者挂掉重新选举后,会根据参与者和原主节点状态确定是执行还是回滚。

新协调者来的时候发现自己是可提交状态并且参与者为可提交和回滚状态,说明经过投票回滚的,此时新协调者执行回滚命令 新协调者来的时候发现自己是预提交并且参与者处于预提交和提交状态,那么表明已经经过了所有参与者的确认了,所以此时执行的就是提交命令

可以看到3PC由于多引入了一个阶段,性能会比较低,而且其实也没有解决数据一致性问题,多了一个阶段的效果也不能保证效果一定要比2PC要好,所以一般还是很少用。

TCC(Try-Confirm-Cancel)

2PC/3PC 模式基于 支持本地 ACID 事务关系型数据库

  • 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
  • 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
  • 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。

相应的,TCC 模式从业务层面处理,不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中,可以不依赖本地数据库,当然实现上可以依赖,更多的场景还是两者结合。

TCC更多的是让业务来实现两阶段提交的思想,对业务侵入性大

Try阶段定义为执行资源的锁定,这个阶段我认为比较难实现,常规的思路是

转账场景时可能需要把尝试账户余额是否足够,然后减去转账金额并把金额存入到临时字段,做到锁定金额 缓存场景可能就需要使用分布式锁,锁定住要操作的缓存值,或者取出某个缓存到另一个缓存 上传下载场景可能需要把文件存到服务器临时目录

Confirm阶段定义为执行try阶段锁定的资源,也就是说基于try的成功,可以继续操作,比如执行真正的转账、缓存操作、上传下载等。

Cancel阶段定义为释放Try预留的资源,也就是说由于Try的失败,需要作出相应的补偿操作或者恢复环境,比如删除掉转账时的临时字段、释放掉锁、清理临时文件等。

TCC模式实现难度还是蛮大的,需要考虑很多异常场景,还要考虑资源如何锁定和释放,但是由于不会阻塞资源,应用方面也更广,据说还是有很多公司热衷于这种补偿型的事务实现方式

还有就是这里所说的TCC更多是一种思想,实际实现可能还是需要根据具体业务来做相应的调整,方法是死的,人是活的。

SAGA

理论基础(点击查看原论文):Hector & Kenneth 发表论文Sagas (1987)

Saga模式提供的是长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

适用场景:

  • 业务流程长、业务流程多
  • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口

Saga主要思想是依赖于状态机转换,长事务拆分成多个短事务,依次执行短事务

如果某个短事务失败,则按照前面执行顺序的逆序执行补偿事务

这种模式还少使用的,实现也是比较复杂,同时流程很长,当遇到类似场景时还是需要仔细考虑是否有必要去实现分布式事务呢?

本地消息表

执行业务的时候 将业务的执行和将消息放入消息表中的操作放在同一个事务中,这样就能保证消息放入本地表中业务肯定是执行成功的。

然后再去调用下一个服务,如果成功了,消息表的消息状态可以直接改成已成功。

如果调用失败,会有 后台任务定时去读取本地消息表,筛选出还未成功的消息再调用对应的服务,服务更新成功了再变更消息的状态。

一般也会有重试次数限制,超出后执行回滚或者通知人工介入。

可见本地消息表也会出现数据不一致的情况,尽量保证最终一致性。

消息队列

此方案的意思是通过支持事务的消息队列来实现分布式事务。

主要流程:

  1. 生产者发送半事务消息到MQ
  2. 生产者收到MQ成功接收到之后,去执行本地事务,但是事务还没有提交。
  3. 生产者会根据事务的执行结果来决定发送提交或者回滚到消息
  4. 生产者需要提供一个查询事务状态接口,如果一段时间内半消息没有收到任何操作请求,那么 MQ 会通过查询接口获得发送方事务执行结果。
  5. 如果是失败结果的消息,MQ直接丢弃,也就不会影响到消费者
  6. 如果是成功结果的消息,消费者消费半事务消息,然后再去消费普通消息

该方案与本地消息不同点是去掉了本地消息表,本地事务和MQ事务绑定在一起。目前市面上实现该方案的应该只有阿里的 RocketMq

最大努力通知

这种方式请进行最大努力自行学习吧

我不懂怎么实现

学了这么多方案,自己实现还是很有难度。

常见的解决方案的实现框架有:byteTCC 、华为 ServiceComb 实现的DTM(华为cloud官网可见)、阿里seata(收费版为GTS)、腾讯DTF

目前开源最火的还是seata,支持模式多、官网文档详细,这里就不一一介绍了

关于seata的文章非常多,下篇文章也打算以seata框架实践分布式事务。

那seata是不是就完美了呢?当然不是,以后可能改进的几点

1、不支持控制台,没有可视化界面,验证全靠打印和连接数据库 2、seata-server高可用不支持Raft协议,事务信息完全依赖于DB、redis等 3、undoLog占用空间过大尤其是前后置镜像一个大JSON字段,数据量大时可能会入库慢,可能需要进行压缩 4、只能通过异常回滚,不支持类似Spring的Rollback-Only标志位回滚 5、全局锁的粒度是不是有点大,分支事务是否有必要上报状态到TC

找到一份seata开源作者 jimin slievrly 的分享视频一起学习

如果需要视频中PPT学习,公众号内回复seata即可

我懂了

本文按照完全没接触过事务的学习流程进行书写,脑图如下:

左边是基础,右边是方案,如果你也在学习分布式事务相关知识,可以参考。

本文是系列第一篇,后面计划一篇为seata实战,一篇为seata原理和如何设计一个通用分布式事务框架。感谢阅读,欢迎关注。

本文分享自微信公众号 - 你呀不牛(notNiu),作者:不牛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-03-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 你还不懂分布式事务吗?

    当系统是分布式系统,并且数据库有分库分表的情况下,此时会产生分布式事务相关的问题。

    Liusy
  • 什么是 “分布式事务” ?

    对于分布式事务,相信所有人都应该很了解,为什么会有分布式事务?无论是数据量导致的分库,还是现在微服务盛行的场景都是他出现的原因。

    小灰
  • 一分钟弄懂什么是分布式和微服务

    原文链接:https://wolzq.com

    林老师带你学编程
  • 为什么大部分NoSQL不提供分布式事务?

    像MongoDB, Cassandra, HBase, DynamoDB, 和 Riak这些NoSQL缺乏传统的原子事务机制,所谓原子事务机制是可以...

    物流IT圈
  • 女朋友问敖丙:什么是分布式事务?

    上一篇文章已经讲完分布式了,那暖男说要讲分布式事务那就一定会讲,只是我估计大家没料到暖男这么快就肝好了吧?

    敖丙
  • 分布式事务系列--是选TCC还是SAGA

    这种模式下,我们需要操作的目标字段,都要添加一个相关的冻结字段,try操作是操作冻结字段,cc操作时,将冻结的数值更新到目标字段。 示例如下:

    IT云清
  • 什么是集群、分布式和微服务?

    通俗解释一下集群:为了建设一栋房子,需要砌砖,一个人砌砖太慢,需要10个人砖瓦工人同事去砌,这样就大大提高了效率,我们说这10个人就组成了一个集群。集群是所有人...

    用户7426861
  • 白话解说,半分钟就懂 --- 分布式与集群是什么 ? 区别是什么?

    后来客人多了,厨房一个厨师忙不过来,又请了个厨师,两个厨师都能炒一样的菜,两个厨师的关系是集群。

    瑞新
  • web服务器集群集群是什么?分布式是什么?集中式是什么?例子缺点

    概述 集群和分布式都是从集中式进化而来的。分布式和集群会相互合作的,同时的集群和分布式。在这里重点说说集群 集群是什么? 集群能提高单位时间内处理的任务数量,提...

    用户1174983
  • 扫盲篇-什么是分布式任务调度

    任务调度是指系统为了自动完成特定任务,在约定的特定时刻去执行任务的过程。有了任务调度即可解放更多的人力由系统自动去执行任务。

    taskctl官方频道
  • 分布式事务之深入理解什么是2PC、3PC及TCC协议?

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

    用户5927304
  • 【DB笔试面试690】在Oracle中,什么是分布式事务处理?

    现代数据库系统往往伴随着复杂的结构和环境,其中,分布式数据库组成是一个重要方面。系统后台的数据库系统不再是由单个数据库构成,而是由多台独立数据库、甚至是多台异构...

    小麦苗DBA宝典
  • 不好意思,懂分布式事务的你真的很了不起,上篇

    分布式事务这个话题,我相信对于身在互联网中的开发者们一定都不陌生。电商系统最容易出现分布式事务的处理,

    架构师修炼
  • 不好意思,懂分布式事务的你真的很了不起,下篇

    上一篇中我们详细分析了分布式事务,以及分布式事务的两种实现方案,二阶段提交和三阶段提交。他们都是满足了事务的ACID特性。但是,他们都有共同的缺点:同步阻塞,系...

    架构师修炼
  • 分布式锁为什么要选择Zookeeper而不是Redis?

    在分布式的应用中,为了防止单点故障,保障高可用,通常会采用主从结构,当主节点挂掉后,从节点可以代替主节点提供服务。

    烂猪皮
  • [源码解析] 并行分布式任务队列 Celery 之 Task是什么

    Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统,专注于实时处理的异步任务队列,同时也支持任务调度。本文目的是看看 Celery 的 task 究...

    罗西的思考
  • 不就是分布式事务,这下彻底清楚了😎

    大家好,我是老三,上次发文的时候还是上次发文的时候,这篇文章分享分布式事务,看完要是你们不懂,那一定是不明白。

    三分恶
  • 不了解分布式事务,大公司怎么敢要你!

    消息中间件在分布式系统中的核心作用就是异步通讯、应用解耦和并发缓冲(也叫作流量削峰)。在分布式环境下,需要通过网络进行通讯,就引入了数据传输的不确定性,也就是C...

    Java编程指南
  • 分布式事务就是这么简单之RocketMQ解决方案

    ​ 现在比较流行的分布式架构而言,它虽然带来一系列好处,比如支持高并发,高可用集群。同时它也带来一系列的挑战,今天我们将的就是其中一种挑战 - 分布...

    yukong

扫码关注云+社区

领取腾讯云代金券