消息队列中的事务是什么呢?

news2024/11/18 9:56:30

消息队列中的事务是什么呢?

说到事务,肯定会优先想到数据库中的事务。在数据库中需要事务,是为了保证数据的一致性、完整性、持久性和隔离性。它可以将数据库中的一组操作合并为一个不可分割的工作单元,要么全部执行成功,要么全部执行失败。那消息队列为什么也需要事务呢?

在很多场景下,我们发消息的目的是为了通知另一个系统或者模块去更新数据,消息队列中的 “事务”,主要解决的是消息生产者和消息消费组的数据一致性问题。

拿电商举例,用户在电商 APP 上购物,先把商品加到购物车里,然后几件商品一起下单,最后支付,完成购物流程。

这个过程中,订单系统创建订单后,发消息给购物车系统,将已下单的商品从购物车中删除。其中,从购物车将已下单的商品删除这个步骤并不是主要流程中的步骤,故可以使用消息队列来异步清理购物车,这样的设计显得更加合理。

对于订单系统来说,它创建订单的过程实际上执行了 2 个步骤的操作:

  1. 在订单库中插入一条订单数据,创建订单;

  2. 发消息给消息队列,内容就是刚刚创建的订单。

购物车系统订阅相关的主题,接收订单发送的消息,然后清理购物车,在购物车中删除订单中的商品。

在分布式系统中,上述的所有操作都有可能会失败,如果不做任何处理,就有可能导致订单数据与购物车数据不一致的问题,比如:

  1. 创建了订单,没有删除购物车

  2. 订单没有创建,购物车里面的商品就被删除了

对于上面第一个问题来说,失败的处理比较简单,只要成功执行清理购物车后再提交消费确认即可,如果执行失败,由于没有提交消费确认,消息队列中不会删除该消息,消息队列会自动重试

问题的关键是第二个问题,创建订单和发送消息两个步骤要么都成功,要么都失败,不允许一个成功另一个失败的情况出现。

这就是事务需要解决的问题。

什么是分布式事务?

通常我们理解的事务是:对若干数据进行更新操作,为了保证这些数据的完整性和一致性,我们希望这些更新操作要么都成功,要么都失败;至于更新的数据,不只局限于数据库中的数据,可以是磁盘上的一个文件,也可以是远端的一个服务,或者以其他形式存储的数据。

一个严格意义的事务实现,应该具有四个特性:原子性、一致性、隔离性、持久性。这四个特性简称 ACID 特性。

原子性,是指一个事务操作不可分割,要么成功,要么失败,不能有一半成功一半失败的情况。

一致性,是指这些数据在事务执行完成这个时间点之前,读到的一定是更新前的数据,之后读到的一定是更新后的数据,不应该存在一个时刻,让用户读到更新过程中的数据。

隔离性,是指一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对正在进行的其他事务是隔离的,并发执行的各个事务之间不能互相干扰,这个有点儿像我们打网游中的副本,我们在副本中打的怪和掉的装备,与其他副本没有任何关联也不会互相影响。

持久性,是指一个事务一旦完成提交,后续的其他操作和故障都不会对事务的结果产生任何影响。

很多单体关系型数据库都实现了完整的 ACID,但是对于分布式系统来说,严格的实现 ACID 这四个特性几乎是不可能的,或者说实现的代价太大,大到我们无法接收。

分布式事务就是指在分布式系统中实现的事务。在分布式系统中,在保证可用性和不严重牺牲性能的情况下,要保证数据的一致性就非常困难了,所以出现了很多残缺版的一致性,比如顺序一致性、最终一致性等。

显然想要实现完整版的分布式系统事务更是不可能完成的任务。所以目前大家所说的分布式事务,更多情况下,是在分布式系统中事务的不完整实现。在不同的应用场景中,有不同的实现,目的都是通过一些妥协来解决实际问题。

在实际应用中,比较常见的分布式事务实现有 2PC(Two-phase Commit,也叫二阶段提交)、TCC(Try-Confirm-Cancel) 和事务消息。每一种实现都有其特定的使用场景,也有各自的问题,都不是完美的解决方案。

事务消息适合的场景主要是那些需要异步更新数据,并且对于数据实时性要求并不高的场景。比如上面提到的订单-购物车案例,在创建订单后,如果出现短暂的几秒,购物车里的商品没有被及时清空,也不是完全不可接受的,只要保证最终购物车的数据和订单数据保持一致即可。

消息队列是如何实现分布式事务的?

要使用事务消息,肯定需要消息队列提供相应的功能才能实现,Kafka 和 RocketMQ 都提供了事务相关功能。

还是订单-购物车的例子,我们一起看下如何使用消息队列来实现分布式事务。

首先,订单系统在消息队列中开启事务。然后订单系统向消息队列服务器发送一个 ”半消息“,这个半消息是一个完整的消息内容,与普通消息的唯一区别就是,在事务提交之前,这个消息对于消费者是不可见的。

半消息发送成功之后,订单系统开始执行本地事务,在订单库中创建一条订单记录,并提交订单库的数据库事务。然后根据本地事务执行结果决定提交或者回滚事务消息。

  • 如果订单创建成功,那就提交事务,购物车系统就可以消费到这条消息,继续后续的处理。

  • 如果订单创建失败,购物车系统就不会收到这条消息。

这样就基本实现了,”要么都成功,要么都失败“ 的一致性要求了。

半消息(也称为预提交消息)是通过一种两阶段提交的方式来确定事务是提交还是回滚的。

发送半消息的时,会包含一个标识,通常为事务 ID 或唯一标识,这个将于本地事务相关联。

如果本地事务执行成功,订单系统决定提交事务消息。它将在消息队列上的半消息标记为“可被消费”,这使得消费者可以看到和处理这条消息。

消费者可以使用事务标识来查找与该消息相关的本地事务状态,根据本地事务状态来决定是否要处理该消息。

上述过程中,还有一个问题是没有解决的:如果在第四步提交事务消息时失败了怎么办?

Kafka 的解决方案比较简单粗暴,直接抛出异常,让用户自行处理。我们可以在代码中反复重试提交,直到成功或者删除之前创建的订单作为补偿。RocketMQ 则给出了另一种解决方案。

RocketMQ 中的分布式事务实现

在 RocketMQ 中的事务实现中,增加了事务反查的机制来解决事务消息提交失败的问题。如果 Prodcuer 也就是订单系统,在提交事务或者回滚事务时发生网络异常,RocketMQ 的 Broker 没有收到提交或者回滚的请求。

Borker 会定期去 Producer 上反查这个事务对应的本地事务的状态,然后根据反查结果决定提交或者回滚这个事务。

为了支撑这个事务反查机制,我们的业务代码需要实现一个反查本地事务状态的接口,告知 RocketMQ 本地事务是成功还是失败。

在我们这个例子中,反查本地事务的逻辑很简单,只需要根据消息中的订单 ID,去订单库中查询是否存在即可,存在则返回成功,反之返回失败。RocketMQ 会自动根据事务反查的结果提交或回滚事务消息。

这个反查本地事务的实现,并不依赖消息的发送方,也就是订单服务的某个实例节点上的任务数据。这种情况下,即使是发送事务消息的那个订单服务节点宕机了,RocketMQ 依然可以通过查询其他服务节点来执行反查,确保事务的完成性。

综合上面讲的通用事务消息的实现和 RocketMQ 的事务反查机制,使用 RocketMQ 事务消息功能实现分布式事务的流程如下图:

小结

通过订单-购物车的案例,学习了事务的 ACID 四大特性,以及如何使用消息队列来实现分布式事务。

然后我们给出了现有的几种分布式事务的解决方案,包括事务消息,但这几种方案都不是银弹,每一种方案都有局限性和特定的使用场景。

最后我们学习了 RocketMQ 的事务反查机制,这张机制通过定期反查事务状态,来补充提交事务消息可能出现的失败问题。在 Kafka 中并没有实现类似的反查机制,需要用户自己去解决这个问题。

但是,这不代表 RocketMQ 的事务功能比 Kafka 更好,只能说在我们这个例子的场景下,更适合使用 RocketMQ。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

​软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】​

软考-高级-系统架构设计师教程(清华第2版)【第4章 信息安全技术基础知识(P160~189)-思维导图】 课本里章节里所有蓝色字体的思维导图

【沐风老师】3dMax使用克隆修改器插件创建旋转楼梯教程

3DMAX克隆修改器插件,它通过增量平移、旋转和缩放输入几何体来创建对象的副本。在某些方面,它类似于 3dMax 的内置“阵列”工具,但有一个主要优点 -克隆修改器是完全参数化的,因此您可以随时更改重复项的数量及其分布。其他功能包…

mapboxGL中的底图切换

概述 底图切换,这么简单的功能还要写一篇文章?值得的,为什么这么说呢?因为mapboxGL的矢量底图有上百个,不同的底图用的样式、图层的名称、图层的内容、字体库、图标库都不一样,尤其是当地图上已经叠加了很…

展会预告 | 图扑邀您相约高交会-全球清洁能源创新博览会

第二十五届中国国际高新技术成果交易会(简称“高交会”)将在深圳盛大开幕。高交会由商务部、科学技术部、工业和信息化部、国家发展改革委、农业农村部、国家知识产权局、中国科学院、中国工程院和深圳市人民政府共同举办。是目前中国规模最大、最具影响力的科技类展会。 图扑软…

【LittleXi】C程序预处理、编译、汇编、链接步骤

【LittleXi】C程序预处理、编译、汇编、链接步骤 C程序 #include<stdio.h> int main(){int x1,y1;printf("xy%d",xy); }1、预处理 将头文件引入进来、除去注释、宏定义下放 执行指令 g -E esc.c -o esc.i 2、编译 将处理好的代码编译为汇编代码.s 执行…

AI优秀企业案例——机器人流程自动化:达观数据RPA

通过学习业内领先公司的最佳实践&#xff0c;我们可以更好地将它们应用到我们自己的公司和业务中。特别是第三部分&#xff0c;提供了大量应用案例&#xff0c;让我们一起期待看到这些案例的结尾。 1.简介 达观数据是一家专注于智能文本机器人的国家高新技术企业&#xff0c;…

Flink SQL -- 反压

1、测试反压&#xff1a; 1、反压&#xff1a; 指的是下游消费数据的速度比上游产生数据的速度要小时会出现反压&#xff0c;下游导致上游的Task反压。 2、测试反压&#xff1a;使用的是DataGen CREATE TABLE words (word STRING ) WITH (connector datagen,rows-per-second…

C# 使用AForge调用摄像头

C# 使用AForge调用摄像头 安装AForge使用AForge控件示例代码 AForge官网 安装AForge Visual Studio 2022>项目>管理NuGet程序包&#xff0c;搜索AForge并依次安装作者为AForge.NET的多个关联组件。 使用AForge控件 安装AForge组件完成后&#xff0c;工具箱会新增AF…

【反编译系列】一、反编译 .so 文件(IDA Pro)

文章目录 【反编译系列】一、反编译 .so 文件&#xff08;IDA Pro&#xff09;1. 介绍2. 反编译Reference 【反编译系列】一、反编译 .so 文件&#xff08;IDA Pro&#xff09; 1. 介绍 .so 文件是共享对象文件&#xff08;Shared Object file&#xff09;的一种形式&#xf…

【Cookie 和 session 的区别】

会话&#xff08;Session&#xff09; 跟踪是Web程序中常用的技术&#xff0c;用来跟踪用户的整个会话。cookie和session都是用来跟踪浏览器用户身份的会话方式。Cookie通过在客户端记录信息确定用户身份&#xff0c;Session通过在服务器端记录信息确定用户身份。 我们目前使用…

网络之路25:VLAN进阶实验-Super VLAN

正文共&#xff1a;1333 字 13 图&#xff0c;预估阅读时间&#xff1a;1 分钟 目录 网络之路第一章&#xff1a;Windows系统中的网络 0、序言 1、Windows系统中的网络1.1、桌面中的网卡1.2、命令行中的网卡1.3、路由表1.4、家用路由器 网络之路第二章&#xff1a;认识企业设备…

【verilog】verilog语法刷题知识点总结

verilog语法刷题知识点总结 1.状态机2.任务和函数的区别3.case&#xff0c;casez和casex4.随机数产生关键字5.运算符优先级6.运算符的特殊注意点及特殊运算符(1)移位运算符(2)等式运算符(3)动态位宽截取运算符(4)求余运算符&#xff08;%&#xff09; 7.testbench知识点8.乘法器…

CTFSHOW -SQL 注入

重新来做一遍 争取不看wp web171 基本联合注入 拿到题目我们已经知道了是sql注入 所以我们可以直接开始 第一题 不会难道哪里去 所以我们直接进行注入即可 1 and 12-- 1 and 11-- 实现闭合 -1unionselect1,2,3--%2b 查看字段数-1unionselect1,database(),3--%2b 查看数据…

【vue】虚拟dom的原理是什么?手写实现虚拟dom !

1.虚拟dom的原理 虚拟 DOM 是对 DOM 的抽象&#xff0c;本质上就是用 JavaScript 对象来描述 DOM 结构。Vue.js 中关于虚拟 DOM 的实现主要进行了以下几个步骤&#xff1a; 1.生成虚拟 DOM&#xff1a; Vue.js 使用 render 函数来依据模板代码生成虚拟 DOM。在这个过程中&a…

Ansible playbook详解

playbook是ansible用于配置&#xff0c;部署&#xff0c;和被管理被控节点的剧本 playbook常用的YMAL格式&#xff1a;&#xff08;文件名称以 .yml结尾&#xff09; 1、文件的第一行应该以 "---" (三个连字符)开始&#xff0c;表明YMAL文件的开始。    2、在同一…

颜值实力“C位出道”:起亚EV6综合实力究竟怎么样?

作为起亚电动化转型的标杆之作&#xff0c;起亚EV6已在全球赢得广泛赞誉&#xff0c;连续斩获“2022欧洲年度汽车”及“2023北美年度汽车”等多项国际大奖&#xff0c;其GT版本更是荣获“2023年度世界性能车”&#xff0c;这些荣誉不仅标志着其设计和技术的国际认可&#xff0c…

安全区域边界(设备和技术注解)

网络安全等级保护相关标准参考《GB/T 22239-2019 网络安全等级保护基本要求》和《GB/T 28448-2019 网络安全等级保护测评要求》 密码应用安全性相关标准参考《GB/T 39786-2021 信息系统密码应用基本要求》和《GM/T 0115-2021 信息系统密码应用测评要求》 1边界防护 1.1应保证跨…

数据结构与算法之美学习笔记:18 | 散列表(上):Word文档中的单词拼写检查功能是如何实现的?

目录 前言散列思想散列函数散列冲突解答开篇 前言 本节课程思维导图&#xff1a; Word 的单词拼写检查功能&#xff0c;虽然很小但却非常实用。你有没有想过&#xff0c;这个功能是如何实现的呢&#xff1f;其实啊&#xff0c;一点儿都不难。只要你学完今天的内容&#xff0c;…

DDD领域驱动设计模式结构图面向接口编程

DDD领域驱动设计模式结构图面向接口编程 9.资源库 在刚接触资源库(Repository)时&#xff0c;第一反应便是这就是个 DAO 层&#xff0c;访问数据库&#xff0c;然后吧啦吧啦&#xff0c;但是&#xff0c;当接触的越久&#xff0c;越发认识到第一反应是错的&#xff0c;资源库更…

HTML5学习系列之主结构

HTML5学习系列之主结构 前言HTML5主结构定义页眉定义导航定义主要区域定义文章块定义区块定义附栏定义页脚 具体使用总结 前言 学习记录 HTML5主结构 定义页眉 head表示页眉&#xff0c;用来表示标题栏&#xff0c;引导和导航作用的结构元素。 <header role"banner…