专栏首页分布式架构分布式架构设计篇(十)-柔性事务之事务消息详解
原创

分布式架构设计篇(十)-柔性事务之事务消息详解

- 概述 -

在 《柔性事务之TCC详解》 和《柔性事务之Saga详解》两文中我们详细剖析了柔性事务的第一个分支补偿型事务。在《刚性事务总结和柔性事务概述》中我们介绍过的柔性事务包含补偿型事务和通知型事务。

通知型事务主要包含事务消息和最大努力通知事务两个组成。通知型事务的主流实现机制是通过MQ来通知其他事务参与者自己事务的执行状态。MQ组件的引入有效的讲事务参与者解耦开,各个参与者都可以异步执行,所以通知型事务又称为异步事务。通知型事务主要适用于那些需要异步更新数据,并且对数据的实时性要求较低的场景。

事务消息主要适用于内部系统的数据最终一致性保障,因为内部相对比较可控,比如订单和购物车、收货与清算、支付与结算等等场景;而最大努力通知事务主要用于外部系统,因为外部的网络环境更加复杂和不可信,所以只能尽最大努力去通知实现数据最终一致性,比如充值平台与运营商、支付对接等等跨网络系统级别对接。

普通消息是无法解决本地事务执行和消息发送的一致性问题的。因为消息发送是一个网络通信的过程,发送消息的过程就有可能出现发送失败、或者超时的情况。超时有可能发送成功了,有可能发送失败了,消息的发送方是无法确定的,所以此时消息发送方无论是提交事务还是回滚事务,都有可能不一致性出现。所以事务消息的难度在于投递消息和参与者自身本地事务的一致性保障。目前业界解决这个一致性的方案有两个分支:

  • 基于MQ自身的事务消息方案
  • 基于DB的本地消息表方案
- 基于MQ自身的事务消息方案 -

基于MQ的事务消息方案主要依靠MQ的半消息机制来实现投递消息和参与者自身本地事务的一致性保障。半消息机制实现原理其实借鉴的2PC的思路,是二阶段提交的广义拓展,流程图如下:

​事务发起方首先发送prepare消息到MQ;

  1. 在发送prepare消息成功后执行本地事务;
  2. 根据本地事务执行结果返回commit或者是rollback;
  3. 如果消息是rollback, MQ将删除该prepare消息不进行下发,如果是commit消息,MQ将会消息发送给consumer端;
  4. 如果执行本地事务过程中,执行端挂掉,或者超时,MQ服务器端将不停的询问producer来获取事务状态;
  5. Consumer端的消费成功机制有MQ保证

MQ事务消息方案因为使用了半消息机制,对业务页具有比较大侵入性,有以下注意点:

  1. 业务方调用半消息,并提供对应的回查方法;
  2. MQ提要提供半消息机制,并定期扫描长期半消息,对消息生产者进行回查确认事务。
  3. 消费方需要进行幂等消费。
- 基于BD的本地消息表方案 -

有时候我们目前的MQ组件并不支持事务消息,或者我们想尽量少的侵入业务方。这时我们需要另外一种方案“基于DB本地消息表",流程图如下:

  • 业务方:直接利用本地事务,将业务数据和事务消息直接写入数据库。
  • 投递线程:使用专门的投递工作线程进行事务消息投递到MQ,根据投递ACK去删除事务消息表记录

本地事务消息表的优势在于方案的通用性,无需提供回查方法,进一步减少的业务的侵入。在某些场景下,还可以进一步利用注解等形式进行解耦,有可能实现无业务代码侵入式的实现。我们上面说了本地事务消息表的基本理论,那么如果要设计一个高可用的企业级本地事务消息表方案,就要考虑更多的事情,在性能上做更大的优化,降低更多的重复投递率。以下是一个企业级事务消息的设计流程图:

  1. 事务消息服务:提供通用投递接口,用于保证事务消息的本地写入,并将事务消息写入事务内存队列。
  2. 使用投递线程池,继续事务内存队列投递派发分配。投递工作线程只投递本实例拥有的事务消息,投递失败线程列入时间轮队列;重试机制使用失败挡位区分,默认提供6档:5s、10s、15s、20s、25s、30s。
  3. 时间轮线程进行60秒转动,将到期的失败事务消息重入事务内存队列.
  4. 因为我们的事务消息服务是无状态化的多实例存在,所以需要一个持锁线程进行主节点竞争强锁,处理一些额外的工作。
  5. 因为我们的事务内存队列是内存级,不可避免面临重启等情况下的数据丢失。这时需要事务消息服务主节点进行定期扫表,将长期未投递的事务消息取出放入事务消息服务。
  6. 事务消息服务主节点还有一个清理线程,专门用于将已处理成功的历史事务消息进行归档清理,降低DB的数据量。
- 总结 -

咱们上面介绍了MQ事务消息方案和DB本地消息表方案,这两个方案有什么区别呢?

  • MQ事务消息方案
    • 需要MQ支持半消息机制或者类似特性,在重复投递上具有比较好的去重处理
    • 需要业务方进行改造,提供对应的本地操作成功回查功能。具有比较大的业务侵入性。
  • DB本地事务消息表方案
    • 使用了数据库来存储事务消息,降低了对MQ的需求,但是增加了存储成本。
    • 事务消息使用了异步投递,增大了消息重复投递的可能性。

我们说了两种事务消息的特性和优劣性,我们在总结下事务消息的共性。

  1. 事务消息都依赖MQ进行事务通知,所以都是异步的。
  2. 事务消息在投递方都是存在重复投递的可能,需要有配套的机制去降低重复投递率,实现更友好的消息投递去重。
  3. 事务消息的消费方,因为投递重复的无法避免,因此需要进行消费去重设计或者服务幂等设计。
- 作者介绍 -

孙玄

毕业于浙江大学,奈学教育创始人兼CEO,前转转公司技术委员会主席,前58集团技术委员会主席,前百度资深研发工程师,腾讯云TVP,阿里云MVP,在线直播大课《百万架构师》品牌创始人。

林淮川

毕业于西安交通大学;奈学教育《百万架构师训练营》讲师及企业级源码内源负责人,前大树金融高级架构师;前大树金融技术委员会开创者;前大树金融供应链金融技术总监;前天阳宏业交易事业部技术主管;多年互联网金融行业(ToB)经验。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 分布式架构设计篇(十一)-柔性事务之最大努力通知事务详解

    ​ 咱们在上一篇文章探讨了事务消息,事务消息是基于MQ实现的一种异步事务。接下来咱们开始聊聊咱们分布式事务系列中的最后一个方案:最大努力通知事务。最...

    林淮川
  • 分布式架构设计篇(七)-刚性事务总结和柔性事务概述

    ​ 在《分布式架构之设计篇-刚性事务之2PC详解》和《分布式架构之设计篇-刚性事务之3PC详解》二文中分析了分布式事务的本质、XA、2PC、3PC等...

    林淮川
  • 分布式架构设计篇(九)-柔性事务之Saga详解

    ​ Saga模型起源于1987年 Hector Garcia-Molina,Kenneth Salem 发表的论文《Sagas》,是分布式事务相关概念...

    林淮川
  • 分布式柔性事务之事务消息详解

    在 《柔性事务之TCC详解》 和《柔性事务之Saga详解》两文中我们详细剖析了柔性事务的第一个分支补偿型事务。在《刚性事务总结和柔性事务概述》中我们介绍过的柔性...

    江帅帅
  • 分布式柔性事务之事务消息详解

    在 《柔性事务之TCC详解》 和《柔性事务之Saga详解》两文中我们详细剖析了柔性事务的第一个分支补偿型事务。在《刚性事务总结和柔性事务概述》中我们介绍过的柔性...

    孙玄@奈学教育
  • 分布式事务利器——RocketMQ事务消息的启示

    我们以一个转帐的场景为例来说明这个问题,Bob向Smith转账100块。这个列子在瓜子也有很多实际场景映射,如:车源状态变化,订单状态变化,金融放款,物流运输…...

    普通程序员
  • 事务Transaction

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务结束(...

    职场亮哥
  • Mysql学习笔记【事务篇】

    当数据库中一个事务A正在修改一个数据但是还未提交或者回滚时,另一个事务B 来读取了修改后的内容并且使用了,然后事务A进行了提交,此时就引起了脏读。

    秦穆之
  • MySQL事务锁问题-Lock wait timeout exceeded

      接口响应时间超长,耗时几十秒才返回错误提示,后台日志中出现Lock wait timeout exceeded; try restarting transa...

    JouyPub
  • 3-1 SQL Server 2005的

    所谓事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。SQL Server 2005 提供了几种自动的可以通过编程来完成...

    py3study

扫码关注云+社区

领取腾讯云代金券