一、 前言

阿里2017云栖大会《破解世界性技术难题!GTS让分布式事务简单高效》中,阿里声称提出了一种破解世界性难题之分布式事务的终极解决方案,无论是可靠性、还是处理速率都领先于市面上所有的技术。但令人遗憾的是一来项目未开源,二来还必须依赖阿里云的分布式数据库。毕竟,吃饭的家伙可不能轻易示人嘛

虽然如此,但《世界难题...》一文中对事务还是归纳的还是蛮到位的:“一个看似简单的功能,内部可能需要调用多个“服务”并操作多个数据库或分片来实现,单一技术手段和解决方案已无法满足这些复杂应用场景。因此,分布式系统架构中分布式事务是一个绕不过去的挑战。

什么是分布式事务?简单的说,就是一次大操作由不同小操作组成,这些小操作分布在不同服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。”

举个栗子:

你上Taobao买东西,需要先扣钱,然后商品库存-1吧。但扣款和库存分别属于两个服务,这两个服务中间要经过网络、网关、主机等一系列中间层,万一任何一个地方出了问题,比如网络抖动、突发异常等待,都会导致不一致,比如扣款成功了,但是库存没-1,就会出现超卖的现象,而这就是分布式事务需要解决的问题

二 2阶段提交(2PC, 3PC等)

2阶段提交是分布式事务传统解决方案,先进为止还广泛存在。当一个事务跨越多个节点时,为了保持事务ACID特性,需要引入一个作为协调者来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

以开会为例

甲乙丙丁四人要组织一个会议,需要确定会议时间,不妨设甲是协调者,乙丙丁是参与者。

投票阶段

  1. 甲发邮件给乙丙丁,周二十点开会是否有时间;
  2. 甲回复有时间;
  3. 乙回复有时间;
  4. 丙迟迟不回复,此时对于这个活动,甲乙丙均处于阻塞状态,算法无法继续进行;
  5. 丙回复有时间(或者没有时间);

提交阶段

  1. 协调者甲将收集到的结果反馈给乙丙丁(什么时候反馈,以及反馈结果如何,在此例中取决与丙的时间与决定);
  2. 乙收到;
  3. 丙收到;
  4. 丁收到;

不仅要锁住参与者的所有资源,而且要锁住协调者资源,开销大。一句话总结就是:2PC效率很低,对高并发很不友好。

引用《世界性难题...》一文原话 "国外具有几十年历史和技术沉淀的基于XA模型的商用分布式事务产品,在相同软硬件条件下,开启分布式事务后吞吐经常有数量级的下降。"

此外还有三阶段提交

三 柔性事务

所谓柔性事务是相对强制锁表的刚性事务而言。流程入下:服务器A的事务如果执行顺利,那么事务A就先行提交,如果事务B也执行顺利,则事务B也提交,整个事务就算完成。但是如果事务B执行失败,事务B本身回滚,这时事务A已经被提交,所以需要执行一个补偿操作,将已经提交的事务A执行的操作作反操作,恢复到未执行前事务A的状态。

缺点是业务侵入性太强,还要补偿操作,缺乏普遍性,没法大规模推广。

四 消息最终一致性解决方案之RocketMQ

目前基于消息队列的解决方案有阿里的RocketMQ,它实现了半消息的解决方案,有点类似于Paxos算法。

第一阶段:上游应用执行业务并发送MQ消息

  1. 上游应用发送待确认消息到可靠消息系统
  2. 可靠消息系统保存待确认消息并返回
  3. 上游应用执行本地业务
  4. 上游应用通知可靠消息系统确认业务已执行并发送消息。

可靠消息系统修改消息状态为发送状态并将消息投递到 MQ 中间件

第二阶段:下游应用监听 MQ 消息并执行业务

下游应用监听 MQ 消息并执行业务,并且将消息的消费结果通知可靠消息服务。

  1. 下游应用监听 MQ 消息组件并获取消息
  2. 下游应用根据 MQ 消息体信息处理本地业务
  3. 下游应用向 MQ
  4. 确认消息被消费
  5. 下游应用通知可靠消息系统消息被成功消费,可靠消息将该消息状态更改为已完成

  RocketMQ貌似是一种先进的实现方案了,但问题是缺乏文档,无论是在Apache项目主页,还是在阿里的页面上,最多只告诉你如何用,而原理性或者指导性的东西非常缺乏。

当然,如果你在阿里云上专门购买了RocketMQ服务,想必是另当别论了。但如果你试图在自己的服务环境中部署和使用,想必要历经相当大的学习曲线。

四、 消息最终一致性解决方案之RabbitMQ实现

  RabbitMQ遵循了AMQP规范,用消息确认机制来保证:只要消息发送,就能确保被消费者消费来做到了消息最终一致性。而且开源,文档还异常丰富,貌似是实现分布式事务的良好载体

4.1 RabbitMQ消息确认机制

rabbitmq的整个发送过程如下

1. 生产者发送消息到消息服务

2. 如果消息落地持久化完成,则返回一个标志给生产者。生产者拿到这个确认后,才能放心的说消息终于成功发到消息服务了。否则进入异常处理流程。

3. 消息服务将消息发送给消费者

4. 消费者接受并处理消息,如果处理成功则手动确认。当消息服务拿到这个确认后,才放心的说终于消费完成了。否则重发,或者进入异常处理。

4.2 异常

我们来看看可能发送异常的四种

1. 直接无法到达消息服务

网络断了,抛出异常,业务直接回滚即可。如果出现connection closed错误,直接增加 connection数即可

connectionFactory.setChannelCacheSize(100);

2. 消息已经到达服务器,但返回的时候出现异常

rabbitmq提供了确认ack机制,可以用来确认消息是否有返回。因此我们可以在发送前在db中(内存或关系型数据库)先存一下消息,如果ack异常则进行重发. 其实就是生产者推送消息后,触发的回调方法里做处理。

    /**confirmcallback用来确认消息是否有送达消息队列*/     rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {if (!ack) {//try to resend msg} else {//delete msg in db}});/**若消息找不到对应的Exchange会先触发returncallback */rabbitTemplate.setReturnCallback((message, replyCode, replyText, tmpExchange, tmpRoutingKey) -> {try {Thread.sleep(Constants.ONE_SECOND);} catch (InterruptedException e) {e.printStackTrace();}log.info("send message failed: " + replyCode + " " + replyText);rabbitTemplate.send(message);});

3. 消息送达后,消息服务自己挂了

如果设置了消息持久化,那么ack= true是在消息持久化完成后,就是存到硬盘上之后再发送的,确保消息已经存在硬盘上,万一消息服务挂了,消息服务恢复是能够再重发消息

4. 未送达消费者

消息服务收到消息后,消息会处于"UNACK"的状态,直到客户端确认消息

  • deliveryTag:该消息的index

  • multiple:是否批量. true:将一次性ack所有小于deliveryTag的消息。

channel.basicAck(envelope.getDeliveryTag(), false);

5. 确认消息丢失

消息返回时假设确认消息丢失了,那么消息服务会重发消息。注意,如果你设置了autoAck= false,但又没应答channel.baskAck也没有应答channel.baskNack,那么会导致非常严重的错误:消息队列会被堵塞住,所以,无论如何都必须应答

6. 消费者业务处理异常

消息监听接受消息并处理,假设抛异常了,第一阶段事物已经完成,如果要配置回滚则过于麻烦,即使做事务补偿也可能事务补偿失效的情况,所以这里可以做一个重复执行,比如guavaretry,设置一个指数时间来循环执行,如果n次后依然失败,发邮件、短信,用人肉来兜底。

最后个人提一句:

选择哪种解决方案,思维不能定死,文章里的顶多提供一些思路。

是选择采取加入中间件? 还是采取手动保证事务? 还是采取补救方式?

这些东西没有固定的说法,只有根据自己当前项目场景,团队情况,业务需求及可接受程度等等诸多因素 去选择适宜的方案。

微服务 分布式事务解决方案相关推荐

  1. 微服务分布式事务解决方案Seata

    文章目录 一.Seata是什么? 二.使用步骤 1.引入库 2.读入数据 总结 一.什么是Seata? Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用 的分布式事务服务.Sea ...

  2. seata xid是什么_微服务分布式事务解决方案-springboot整合分布式seata1.3.0

    概述 Seat是蚂蚁金服和阿里巴巴联合推出的一个开源的分布式事务框架,在阿里云商用的叫做GTS. 项目地址:https://github.com/longxiaonan/springcloud-dem ...

  3. 一行代码就能解决微服务分布式事务问题,你知道GTS怎么做到的吗?

    2019独角兽企业重金招聘Python工程师标准>>> GTS直播火热报名中,直播直通车 一.GTS (Global Transaction Service)是啥? GTS(全局事务 ...

  4. seata 如何开启tcc事物_微服务分布式事务4种解决方案实战

    分布式事务 分布式事务是指事务的参与者,支持事务的服务器,资源服务器分别位于分布式系统的不同节点之上,通常一个分布式 事物中会涉及到对多个数据源或业务系统的操作. 典型的分布式事务场景:跨银行转操作就 ...

  5. 同事操作两个数据源保持事务一致_微服务分布式事务4种解决方案实战

    分布式事务 分布式事务是指事务的参与者,支持事务的服务器,资源服务器分别位于分布式系统的不同节点之上,通常一个分布式 事物中会涉及到对多个数据源或业务系统的操作. 典型的分布式事务场景:跨银行转操作就 ...

  6. 微服务-分布式事务seata

    什么是分布式事务 单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源, 业务操作需要调用三个服务来完成.此时每个服务内部的数据一致性由本地事务来保证,但是全局的 ...

  7. 微服务--分布式事务的实现方法及替代方案

    这两天正在研究微服务架构中分布式事务的处理方案, 做一个小小的总结, 作为备忘. 如有错误, 欢迎指正! 概念澄清 事务补偿机制: 在事务链中的任何一个正向操作, 都必须存在一个完全符合回滚规则的可逆 ...

  8. 微服务~分布式事务里的最终一致性

    本地事务ACID大家应该都知道了,统一提交,失败回滚,严格保证了同一事务内数据的一致性!而分布式事务不能实现这种ACID,它只能实现CAP原则里的某两个,CAP也是分布式事务的一个广泛被应用的原型,C ...

  9. .Net Core with 微服务 - 分布式事务 - 2PC、3PC

    最近比较忙,好久没更新了.这次我们来聊一聊分布式事务. 在微服务体系下,我们的应用被分割成多个服务,每个服务都配置一个数据库.如果我们的服务划分的不够完美,那么为了完成业务会出现非常多的跨库事务.即使 ...

最新文章

  1. 关于微阵列芯片和RNA-seq的比较
  2. 在线代码格式化,在线JSON校验格式化
  3. 图深度学习(GraphDL),下一个人工智能算法热点
  4. Java的Excel导出方案介绍
  5. nginx php 配置
  6. JetBrains:修改C盘中的JetBrains家族软件如PyCharm、WebStorm等的缓存文件位置
  7. 【转】HEIF图片存储格式探秘
  8. 51CTO网友感谢信:昨天以940分的成绩顺利通过NE考试 在此特地感谢网工泡泡
  9. 中国计算机类研究生学校排名,2018考研:计算机专业全球院校排名公布,上海交通大学竟排第一?...
  10. 计算机相关专业EI及SCI国际会议及期刊汇总
  11. linux 儒略日时间计算,C/C++ 儒略日计算以及恒星时计算
  12. 微信商户中查看 appid
  13. html中设置首字母大写,css如何设置英文首字母大写
  14. CSS(持续更新。。)
  15. OA系统,满足各行业办公所需的管理软件
  16. uniapp中上传图片
  17. MySQL架构介绍(一)
  18. kali攻击wifi、破解wifi详细教程(仅供学习使用)
  19. Linux Oracle dbf文件误删 恢复操作
  20. 数据结构 图的邻接表和邻接矩阵实现———c语言

热门文章

  1. 【游戏建模全流程】Maya如何建模神秘的房子模型
  2. SD卡插上上网本时显示文件夹变成文件请问怎么才能修复
  3. 不用代码快速将Excel的数据导入SQL Server数据库中
  4. CentOS 7安装Jenkins
  5. witter Storm 安装实战
  6. 【java基础06:数据类型】及拓展、转义字符、计算机二进制的表现形式
  7. aiomysql + sqlalchemy(ORM) 配合使用
  8. R语言实现拟合神经网络预测和结果可视化
  9. 「Do.017」如何高效使用Win电脑?
  10. 41 freertos内存管理试验 1