分布式事物 - 如何解决分布式事务问题?

面试题

分布式事务了解吗?你们是如何解决分布式事务问题的?

面试官心理分析

只要聊到你做了分布式系统,必问分布式事务,你对分布式事务一无所知的话,确实会很坑,你起码得知道有哪些方案,一般怎么来做,每个方案的优缺点是什么。

现在面试,分布式系统成了标配,而分布式系统带来的分布式事务也成了标配了。因为你做系统肯定要用事务吧,如果是分布式系统,肯定要用分布式事务吧。先不说你搞过没有,起码你得明白有哪几种方案,每种方案可能有啥坑?比如 TCC 方案的网络问题、XA 方案的一致性问题。

面试题剖析

分布式事务的实现主要有以下 5 种方案:

  • XA 方案
  • TCC 方案
  • 本地消息表
  • 可靠消息最终一致性方案
  • 最大努力通知方案

两阶段提交方案/XA方案

所谓的 XA 方案,即:两阶段提交,有一个事务管理器的概念,负责协调多个数据库(资源管理器)的事务,事务管理器先问问各个数据库你准备好了吗?如果每个数据库都回复 ok,那么就正式提交事务,在各个数据库上执行操作;如果任何其中一个数据库回答不 ok,那么就回滚事务。

这种分布式事务方案,比较适合单块应用里,跨多个库的分布式事务,而且因为严重依赖于数据库层面来搞定复杂的事务,效率很低,绝对不适合高并发的场景。如果要玩儿,那么基于 Spring + JTA 就可以搞定,自己随便搜个 demo 看看就知道了。

这个方案,我们很少用,一般来说某个系统内部如果出现跨多个库的这么一个操作,是不合规的。我可以给大家介绍一下, 现在微服务,一个大的系统分成几十个甚至几百个服务。一般来说,我们的规定和规范,是要求每个服务只能操作自己对应的一个数据库

如果你要操作别的服务对应的库,不允许直连别的服务的库,违反微服务架构的规范,你随便交叉胡乱访问,几百个服务的话,全体乱套,这样的一套服务是没法管理的,没法治理的,可能会出现数据被别人改错,自己的库被别人写挂等情况。

如果你要操作别人的服务的库,你必须是通过调用别的服务的接口来实现,绝对不允许交叉访问别人的数据库。

TCC 方案

TCC 的全称是:Try、Confirm、Cancel。

  • Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行锁定或者预留
  • Confirm 阶段:这个阶段说的是在各个服务中执行实际的操作
  • Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚)

这种方案说实话几乎很少人使用,我们用的也比较少,但是也有使用的场景。因为这个事务回滚实际上是严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大,非常之恶心。

比如说我们,一般来说跟相关的,跟钱打交道的,支付交易相关的场景,我们会用 TCC,严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性,保证在资金上不会出现问题。

而且最好是你的各个业务执行的时间都比较短。

但是说实话,一般尽量别这么搞,自己手写回滚逻辑,或者是补偿逻辑,实在太恶心了,那个业务代码很难维护。

本地消息表

本地消息表其实是国外的 ebay 搞出来的这么一套思想。

这个大概意思是这样的:

  1. A 系统在自己本地一个事务里操作同时,插入一条数据到消息表;
  2. 接着 A 系统将这个消息发送到 MQ 中去;
  3. B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息
  4. B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态;
  5. 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理;
  6. 这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。

这个方案说实话最大的问题就在于严重依赖于数据库的消息表来管理事务啥的,会导致如果是高并发场景咋办呢?咋扩展呢?所以一般确实很少用。

可靠消息最终一致性方案

这个的意思,就是干脆不要用本地的消息表了,直接基于 MQ 来实现事务。比如阿里的 RocketMQ 就支持消息事务。

大概的意思就是:

  1. A 系统先发送一个 prepared 消息到 mq,如果这个 prepared 消息发送失败那么就直接取消操作别执行了;
  2. 如果这个消息发送成功过了,那么接着执行本地事务,如果成功就告诉 mq 发送确认消息,如果失败就告诉 mq 回滚消息;
  3. 如果发送了确认消息,那么此时 B 系统会接收到确认消息,然后执行本地的事务;
  4. mq 会自动定时轮询所有 prepared 消息回调你的接口,问你,这个消息是不是本地事务处理失败了,所有没发送确认的消息,是继续重试还是回滚?一般来说这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,而确认消息却发送失败了。
  5. 这个方案里,要是系统 B 的事务失败了咋办?重试咯,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚,比如 B 系统本地回滚后,想办法通知系统 A 也回滚;或者是发送报警由人工来手工回滚和补偿。
  6. 这个还是比较合适的,目前国内互联网公司大都是这么玩儿的,要不你举用 RocketMQ 支持的,要不你就自己基于类似 ActiveMQ?RabbitMQ?自己封装一套类似的逻辑出来,总之思路就是这样子的。

最大努力通知方案

这个方案的大致意思就是:

  1. 系统 A 本地事务执行完之后,发送个消息到 MQ;
  2. 这里会有个专门消费 MQ 的最大努力通知服务,这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以,接着调用系统 B 的接口;
  3. 要是系统 B 执行成功就 ok 了;要是系统 B 执行失败了,那么最大努力通知服务就定时尝试重新调用系统 B,反复 N 次,最后还是不行就放弃。

你们公司是如何处理分布式事务的?

如果你真的被问到,可以这么说,我们某某特别严格的场景,用的是 TCC 来保证强一致性;然后其他的一些场景基于阿里的 RocketMQ 来实现分布式事务。

你找一个严格资金要求绝对不能错的场景,你可以说你是用的 TCC 方案;如果是一般的分布式事务场景,订单插入之后要调用库存服务更新库存,库存数据没有资金那么的敏感,可以用可靠消息最终一致性方案。

友情提示一下,RocketMQ 3.2.6 之前的版本,是可以按照上面的思路来的,但是之后接口做了一些改变,我这里不再赘述了。

当然如果你愿意,你可以参考可靠消息最终一致性方案来自己实现一套分布式事务,比如基于 RocketMQ 来玩儿。

转载来源:https://github.com/doocs/advanced-java/blob/master/docs/distributed-system/distributed-transaction.md

分布式事务 - 如何解决分布式事务问题?相关推荐

  1. 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

    搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...

  2. 基于数据库的事务消息解决分布式事务方案

    转载请注明出处:http://www.cnblogs.com/lizo/p/8516502.html 概述 当单库已不能支撑当前业务的时候,我们往往都考虑进行分库(横向拆分或者纵向拆分).但分库有个无 ...

  3. LCN分布式事务框架解决分布式事务一致性问题

    LCN分布式事务框架 框架介绍 LCN分布式事务框架其本身并不创建事务,而是基于对本地事务的协调从而达到事务一致性的效果. 核心步骤 创建事务组 是指在事务发起方开始执行业务代码之前先调用TxMana ...

  4. Java中的事务——全局事务与本地事务

    转载自   Java中的事务--全局事务与本地事务 在上一篇文章中说到过,Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务. 这是从事务的实现角 ...

  5. rabbitmq 查询版本_基于rabbitmq解决分布式事务

    分布式事务要解决的问题是保证二个数据库数据的一致性,本地事务ACID属于刚性事务,基于CAP理论,分布式事务的核心要点柔性事务,最终一致性. 基于rabbitmq解决分布式事务要点如下 生产者采用发送 ...

  6. RocketMQ如何解决分布式事务

    本文来说下RocketMQ如何解决分布式事务 文章目录 基本实现思路 RocketMQ的事务消息状态 代码实例 maven导入 yaml文件配置 核心代码 本文小结 基本实现思路 核心思想:事务消息总 ...

  7. 基于消息中间件解决分布式事务的开源框架Myth

    基于消息中间件的解决分布式事务框架:https://github.com/yu199195/myth 1.rpc框架支持 : dubbo,motan,springcloud. 2.消息中间件支持 : ...

  8. 分布式事务二——解决思路

    文章目录 一.分布式事务的思路 1.1 CAP定理 1.1.1 Partition tolerance 1.1.2 Consistency 1.1.3 Availability 1.1.4 Consi ...

  9. 解决分布式事务,Seata真香

    目录 背景介绍 什么是分布式事务 什么叫做逆向补偿呢 互联网最流行的分布式事务组件seata 总结 背景 大家好,今天给大家分享一个在 2022 年出去面试 Java 几乎必问的一个技术,那就是 se ...

最新文章

  1. boost::callable_traits添加member右值引用的测试程序
  2. Python基础01-变量及数据类型
  3. Android 性能优化:使用 Lint 优化代码、去除多余资源,减少APP的size
  4. ASP.NET Core 3.0 发布
  5. async和await的错误捕获
  6. Airflow安装教程
  7. react视频教程经典大全
  8. 知网查重报告html乱码,知网查重报告乱码如何解决?
  9. 微信小程序跳转到另一个小程序(往返)
  10. Javascript中Promise对象
  11. Mac升级文件不见了怎么恢复?
  12. Python爬取58同城租房数据,完美解决字体加密
  13. 基于python学生考勤_学生考勤系统(含源代码).pdf
  14. 批量操作:ps怎么(如何)导入图片的方法
  15. CreateDC与CreateCompatibleDC建立的HDC有何不同?
  16. ios rsa加密 java解密_iOS RSA加密与解密 签名与验签(附Java端处理)
  17. 第二题:编写程序,将华氏度转换为摄氏度
  18. 短视频平台推广怎么做
  19. PDF怎么编辑文字?教你两招非常实用的方法
  20. 先定产权还是先定价格,数据交易场景下的市场设计问题,合作博弈中“沙普利值”

热门文章

  1. MongoDB 教程五: MongoDB固定集合和性能优化
  2. PHP 多维数组搜索 PHP multi dimensional array search
  3. 搜索互联网缓存页面 How to View the Cached Page of any URL or Website
  4. MySQL数据库备份的10个教程
  5. 树模型——机器学习面试
  6. 贪心——FatMouse' Trade(hdu1003)
  7. Ubuntu 添加、删除ppa源
  8. django 通过路径传参 视图获取get请求
  9. jquery-文档宽高-窗口宽高-scrollTop与scrollLeft
  10. tar.gz及tar.bz2两种常见格式的打包压缩及解压方法