RocketMQ 事务消息

事务消息是 RocketMQ 的高级特性之一 。这篇文章,笔者会从应用场景功能原理实战例子三个模块慢慢为你揭开事务消息的神秘面纱。

1 应用场景

举一个电商场景的例子:用户购物车结算时,系统会创建支付订单。

用户支付成功后支付订单的状态会由未支付修改为支付成功,然后系统给用户增加积分。

通常我们会使用普通消费方案,该方案能够发挥 MQ 的优势:异步解耦 ,  同时架构设计非常简单。

图片

  1. 用户购物车结算时,系统创建支付订单;

  2. 支付成功后,更新订单的状态从未支付修改为支付成功;

  3. 发送一条普通消息到消息队列服务端;

  4. 积分服务消费消息,添加积分记录。

但该方案有个非常直观的缺点:容易出现不一致的现象

  1. 假如先发送消息,后修改订单状态,消息发送成功,订单没有执行成功,需要回滚整个事务(订单数据事务回滚,积分服务消费时,需要先反查事务状态,若事务提交,才能插入积分记录)。

  2. 假如先修改订单状态,后发送消息,订单状态修改成功,但消息发送失败,需要补偿操作才能保持最终一致。

  3. 假如先修改订单,后发送消息,订单状态修改成功,但消息发送超时,此时无法判断需要回滚订单还是提交订单变更。

我们看到,为了完善普通消费方案,业务层还需要做到两点:补偿机制提供事务状态查询接口

要做到这两点,难不难呢?

不难,但是业务层代码会比较混乱,更优的方案还是得从中间件层面解决。

2 功能原理

RocketMQ 事务消息是支持在分布式场景下保障消息生产和本地事务的最终一致性。交互流程如下图所示:

图片

1、生产者将消息发送至 Broker 。

2、Broker 将消息持久化成功之后,向生产者返回 Ack 确认消息已经发送成功,此时消息被标记为"暂不能投递",这种状态下的消息即为半事务消息

3、生产者开始执行本地事务逻辑

4、生产者根据本地事务执行结果向服务端提交二次确认结果( Commit 或是 Rollback ),Broker 收到确认结果后处理逻辑如下:

  • 二次确认结果为 Commit :Broker 将半事务消息标记为可投递,并投递给消费者。

  • 二次确认结果为 Rollback :Broker 将回滚事务,不会将半事务消息投递给消费者。

5、在断网或者是生产者应用重启的特殊情况下,若 Broker 未收到发送者提交的二次确认结果,或 Broker 收到的二次确认结果为 Unknown 未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查

  1. 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。

  2. 生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。

笔者认为事务消息的精髓在于:

  1. 本地事务执行成功,消费者才能消费事务消息

  2. 消息回查本身就是补偿机制的实现,事务生产者需提供了事务状态查询接口。

3 实战例子

为了便于大家理解事务消息 ,笔者新建一个工程用于模拟支付订单创建支付成功赠送积分的流程。

首先,我们创建一个真实的订单主题:order-topic 。

图片

然后在数据库中创建三张表 订单表事务日志表积分表

图片

最后我们创建一个 Demo 工程,生产者模块用于创建支付订单、修改支付订单成功,消费者模块用于新增积分记录。

图片

接下来,我们展示事务消息的实现流程。

1、创建支付订单

调用订单生产者服务创建订单接口 ,在 t_order 表中插入一条支付订单记录。

图片

2、调用生产者服务修改订单状态接口

接口的逻辑就是执行事务生产者的 sendMessageInTransaction  方法。

图片

生产者端需要配置事务生产者事务监听器

图片

发送事务消息的方法内部包含三个步骤 :

图片

事务生产者首先发送半事务消息,发送成功后,生产者才开始执行本地事务逻辑

事务监听器实现了两个功能:执行本地事务供 Broker 回查事务状态 。

图片

执行本地事务的逻辑内部就是执行 orderService.updateOrder 方法。

方法执行成功则返回 LocalTransactionState.COMMIT_MESSAGE , 若执行失败则返回 LocalTransactionState.ROLLBACK_MESSAGE 。

图片

需要注意的是: orderService.updateOrder 方法添加了事务注解,并将修改订单状态和插入事务日志表放进一个事务内,避免订单状态和事务日志表的数据不一致。

最后,生产者根据本地事务执行结果向 Broker 提交二次确认结果

Broker 收到生产者确认结果后处理逻辑如下:

  • 二次确认结果为 Commit :Broker 将半事务消息标记为可投递,并投递给消费者。

  • 二次确认结果为 Rollback :Broker 将回滚事务,不会将半事务消息投递给消费者。

3、积分消费者消费消息,添加积分记录

当 Broker 将半事务消息标记为可投递时,积分消费者就可以开始消费主题 order-topic 的消息了。

图片

积分消费者服务,我们定义了消费者组名,以及订阅主题消费监听器

图片

在消费监听器逻辑里,幂等非常重要 。当收到订单信息后,首先判断该订单是否有积分记录,若没有记录,才插入积分记录。

而且我们在创建积分表时,订单编号也是唯一键,数据库中也必然不会存在相同订单的多条积分记录。

4 总结

RocketMQ 事务消息是支持在分布式场景下保障消息生产和本地事务的最终一致性

编写一个实战例子并不复杂,但使用事务消息时需要注意如下三点:

1、事务生产者和消费者共同协作才能保证业务数据的最终一致性;

2、事务生产者需要实现事务监听器,并且保存事务的执行结果(比如事务日志表) ;

3、消费者要保证幂等。消费失败时,通过重试告警+人工介入等手段保证消费结果正确。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/57261.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序选项卡切换(滑动切换,点击切换)

效果如下&#xff1a;可点击切换&#xff0c;滑动切换 代码如下 这个可以在项目用 index.wxml <view classtopTabSwiper><view classtab {{currentData 0 ? "tabBorer" : ""}} data-current "0" bindtapcheckCurrent>选项一&…

警惕!中科院预警,Frontiers这本不被收录!2023年7月EI目录已更新!(附全年下载)

2023年7月EI期刊目录更新 爱思唯尔官网近日更新了EI期刊目录&#xff0c;此次更新是2023年7月1日&#xff0c;与上次更新&#xff08;2023年6月&#xff09;相比&#xff0c;有1本期刊名称在Serials&#xff08;连续出版&#xff09;列表中搜索不到&#xff0c;详情如下&#…

Java课题笔记~ 动态SQL详解

一、动态 sql 是什么&#xff1f; 1、动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中&#xff0c;开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。 例如&#xff0c;拼接时要确保添加了必要的空格&#xff0c;还要…

AgileBoot - 全栈项目启动

AgileBoot-Back-End: 基于Ruoyi做了大量重构优化的基础快速开发框架。采用Springboot Vue 3 Mybatis Plus 更面向对象的业务建模 面向生产的项目。&#xff08;非玩具项目&#xff09; 首先克隆代码&#xff0c;同是克隆前端和后端的代码。 前端代码启动&#xff1a; np…

阿里云容器服务 Serverless 版(ACK Serverless)全新升级

7 月 31 日&#xff0c;阿里云智能云原生应用平台负责人丁宇宣布&#xff0c;容器服务 Serverless 版 ACK Serverless 全新升级。 ACK Serverless&#xff1a;免运维、极致弹性的 K8s 全托管服务 阿里云在 2018 年发布了首个 Serverless 容器服务 ASK&#xff0c;其本质是将容…

音视频--DTMF信号发送及检测

参考资料 https://zh.wikipedia.org/wiki/%E5%8F%8C%E9%9F%B3%E5%A4%9A%E9%A2%91 1. DTMF是什么 1.1 DTMF定义 双音多频信号&#xff08;英语&#xff1a;Dual-Tone Multi-Frequency&#xff0c;简称&#xff1a;DTMF&#xff09;&#xff0c;电话系统中电话机与交换机之间…

list删除重复元素几种思路

文章目录 list删除重复元素几种思路hashsetStream流删除所有重复元素 list删除重复元素几种思路 hashset List<String> list2 new ArrayList<>();list2.add("a");list2.add("b");list2.add("a");Set<String> set new HashS…

uni-app 微信小程序自定义导航栏

一、效果图 二、导航栏的组成 上面的导航栏主要由状态栏&#xff08;就是手机电量显示栏&#xff09;和小程序的导航栏组成&#xff0c;android手机一般为48px&#xff0c;ios手机一般为44px 三、开发步骤 1、设置navigationStyle:custom {"path": "pages/v…

1.初识typescript

在很多地方的示例代码中使用的都是ts而不是js&#xff0c;为了使用那些示例&#xff0c;学习ts还是有必要的 JS有的TS都有&#xff0c;JS与TS的关系很像css与less ts在运行前需要先编译为js&#xff0c;浏览器不能直接运行ts 目录 1 编译TS的工具包 1.1 安装 1.2 基本…

【力扣】 12. 整数转罗马数字 模拟

力扣 12. 整数转罗马数字 解题思路 当某个位数的某个数不为4或9时&#xff0c;高位对应的字符总是在低位对应的字符前面。只有当该数为4或9时&#xff0c;低位对应的字符在高位前面。 根据这一特性&#xff0c;我们进行分类讨论。 1.当数为4时&#xff0c;则对应的罗马数为 10 …

有多卷?智慧金融可视化大屏可以这样子

科学技术不断发展&#xff0c;数字化转型不断加快&#xff0c;智慧金融正成为金融业的新引擎。数字孪生、大数据、物联网等新一代信息技术在推动智慧金融更加强调效率、优化精准营销。数据可视化大屏如何为金融单位提供低代码、定制化的服务&#xff0c;让金融单位的数据可视、…

SOME/IP学习笔记1

SOA概念 在SOA中,每个服务就好像我们每一个人在社会中扮演的角色,在对别人提供着服务的同时,同时也享受着别人提供出来的服务,人与人之间,既是彼此独立的,又是需要互相通讯的。服务提供者将功能具象为一组接口,这样使用者就能知道如何调用服务,完成某件事情,得到某个…

文心一言 VS 讯飞星火 VS chatgpt (70)-- 算法导论6.5 9题

九、请设计一个时间复杂度为 (n lgk)的算法&#xff0c;它能够将 k 个有序链表合并为一个有序链表&#xff0c;这里 n 是所有输入链表包含的总的元素个数。(提示:使用最小堆来完成 k 路归并。 文心一言&#xff1a; 要设计一个时间复杂度为 O(n log k) 的算法&#xff0c;将 …

RabbitMQ快速入门

文章目录 1、RabbitMQ的概述1.1、什么是消息队列&#xff1f;1.2、为什么要使用消息队列&#xff1f;1.3、RabbitMQ的特点&#xff1a; 2、RabbitMQ的安装2.1 下载与安装2.2 常用命令 3、RabbitMQ消息发送和接受3.1 消息发送和接受机制3.2 AMQP的消息路由3.3 Exchange(交换机)的…

该选择WPF 还是 Winform?

WPF和WinForms都是.NET平台下的桌面应用程序开发框架&#xff0c;它们各有特点&#xff0c;适用于不同的场景和需求。下面是对WPF和WinForms的一些比较和优劣势&#xff1a;WPF&#xff08;Windows Presentation Foundation&#xff09;&#xff1a;WPF具有强大的图形渲染能力&…

UML—用例图的那些事

目录 背景: 1.用例图的发展史 过程: 1.用例图中的元素和关系 2.应用中的例子 总结&#xff1a; 背景: 1.用例图的发展史 用例图是一种常用的软件工程工具&#xff0c;用于描述系统的功能需求和用户与系统的交互。它在软件开发过程中起到了重要的作用&#xff0c;并且经历了…

使用Vue+CSS实现汉堡图标过渡为叉号图标,有点意思

前言 本文给大家分享三个具有过渡效果的汉堡图标&#xff0c;当点击汉堡图标时&#xff0c;过渡为叉号图标。这种具有过渡特效的图标挺炫酷的&#xff0c;感觉一下子给网页增加一点新颖特色。早在2015年左右&#xff0c;国外挺多优秀门户网站都有使用类似的图标&#xff0c;那…

学无止境·运维高阶③(Mysqldump脚本)

Mysqldump脚本 1、详细脚本2、执行 1、详细脚本 #!/bin/bash mysql_cmd‘-uroot -pRedHat123’ exclude_db‘information_schema|performance_schema|sys’ bak_path/backup/db mysql m y s q l c m d − e ′ s h o w d a t a b a s e s ′ − N ∣ e g r e p − v " {m…

uniapp小程序console.log在微信开发者工具中不打印问题

最近在开发一款uniapp小程序&#xff0c;发现console.log在微信开发者工具中不打印&#xff0c;但在H5页面就能够有打印输出&#xff0c;于是在网上寻找原因… 主要是由于vue.config.js文件中有设置发布时删除console的配置&#xff0c;如下&#xff1a; 官网参考地址&#x…

如何知道企业是否办理过等保备案?哪里可以查询?

对于等保政策细节&#xff0c;大家还存在很多疑问&#xff0c;例如有人在问&#xff0c;如何知道企业是否办理过等保备案&#xff1f;哪里可以查询&#xff1f;今天我们就来简单聊聊&#xff0c;仅供参考。 如何知道企业是否办理过等保备案&#xff1f; 一般企业办理过等保备案…