【RabbitMQ】幂等性、顺序性
幂等性
概述
幂等性是数学和计算机科学中某些运算的性质,他们可以被多次应用,而不会改变初始应用的结果。RabbitMQ的幂等性则是指同一条消息,多次消费,对系统的影响是相同的。
一般消息中间件的消息传输保障分为三个层级:
- 最少一次(At least once):消息绝对不会丢失,但可能会重复传输。
- 恰好一次(Exactly once):每条消息肯定会被传输一次且仅传输一次。
- 最多一次(At most once):消息可能会丢失,但绝对不会重复传输。
RabbitMQ支持最少一次和最多一次。对于恰好一次,RabbitMQ目前做不到,而且很多消息中间件都做不到这一点。
在业务使用中,对于可靠性要求较高的场景,建议使用最少一次,以防消息丢失。最多一次会因为消息发送过程中,网络问题、消费出现异常等种种原因,导致消息丢失。但是最少一次,就会使得消费端可能收到重复的消息,也会造成对同一条消息的多次处理。对于一些比较重要的业务而言,重复处理相同的消息,就会造成严重事故。例如:当用户对一个订单付款之后,因为网络问题,付款成功的结果未返回给订单系统,当用户再次点击付款时,如果系统未做幂等性处理,那就会造成两次扣款。
以下场景可能会导致消息重复发送:
发送时消息重复:当一条消息已被成功发送到Broker并完成持久化,此时出现了网络闪断或者客户端宕机,导致Broker对客户端应答失败,如果此时生产者意识到发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且MessageID也相同的消息。
投递时消息重复:消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候网络中断。为了保证消息至少被消费一次,消息队列会在网络恢复之后再次尝试投递之前已经被处理过的消息,消费者后续会收到两条内容相同并且MessageID也相同的消息。
解决方案
全局唯一ID
首先,为每条消息分配一个唯一标识符,例如雪花算法、UUID等,只要能保证唯一性即可。
其次,消费者收到消息后,先用唯一标识符判断该消息是否已经消费过,如果消费过就直接放弃。
最后,如果没有消费过,消费者就开始消费信息,业务处理成功之后,把唯一标识符保存起来。
可以使用Redis的原子性操作setnx来保证幂等性,将唯一标识符作为KEY放到Redis中。消费消息之前,先SETNX ID 1。如果返回值为1,表示之前没有消费过,正常消费。返回值为0,则表示这条消息之前已消费过,直接抛弃。
业务逻辑判断
在业务逻辑层面实现消息处理的幂等性。
可以使用数据库来保证幂等性,通过检查数据库是否已经存在相关数据记录;也可以使用锁机制来保证幂等性,通过使用乐观锁机制来避免更新已经被其他事务更改的数据;还可以使用相关业务状态来保证幂等性,在消费者处理消息之前,先检查相关的业务状态,确保消息对应的操作尚未执行,然后才进行处理,具体根据业务场景来做。
顺序性
概述
消息的顺序性是指消费者消费的消息和生产者发送消息的顺序是一致的。例如生产者发送的消息依次是msg1、msg2、msg3,那么消费者消费消息的顺序也必须按照msg1、msg2、msg3的顺序进行。
很多业务场景下,消息的消费是不用保证顺序的,比如使用MQ实现订单超时的处理。但是有些业务场景下,可能存在多个消息顺序处理的情况,比如用户信息修改,对同一个用户的同一个资料进行修改,需要保证消息的顺序。
在实际场景中,如果只有一个生产者,也只有一个消费者,并且不考虑消息丢失、网络故障等异常情况,是可以保证消息的顺序性。但是,如果有多个生产者同时发送消息,无法确定消息到达Broker的前后顺序,也就无法验证消息的顺序性。
打破顺序性的场景:
- 多个消费者:当队列配置了多个消费者时,消息可能会被不同的消费者并行处理,从而导致消息处理的顺序性无法保证。
- 网络波动或异常:在消息传递的过程中,如果出现网络波动或异常,可能会导致ACK(消息确认)丢失,从而使得消息被重新入队和重新消费,造成顺序性问题。
- 消息重试:如果消费者在处理消息后未能及时发送确认,或者确认消息在传输过程中丢失,那么MQ可能会认为消息未被成功消费而进行重试,这也可能导致消息处理的顺序性问题。
- 消息路由问题:在复杂的路由场景中,消息可能会根据路由键被发送到不同的队列,从而无法保证全局的顺序性。
- 死信队列:消息因为某些原因进入死信队列,死信队列被消费时,无法保证消息的顺序和生产者发送消息的顺序一致。
打破顺序性的场景包括但不限于以上几种,如果要保证消息的顺序性,那就需要对消息进行进一步的处理。
解决方案
消息顺序性保障分为:局部顺序性保障和全局顺序性保障。
局部顺序性保障指的是在单个队列内部保证消息的顺序。全局顺序性保障指的是在多个队列或多个消费者之间保障消息的顺序。
在实际工作中,全局顺序性难以实现,可以考虑使用业务逻辑来保障顺序性。比如在消息中嵌入序列号,并在消费端进行排序处理。相对而言,局部顺序性更常见,也更容易实现。
RabbitMQ作为一个分布式消息队列,主要优化的是吞吐量和可用性,而不是严格的顺序性保障。如果业务场景确实需要严格的消息顺序,可能需要在应用层面进行额外的设计和实现。
单队列单消费者
最简单的实现顺序性保障的方法一定是,使用单个队列,并由单个消费者进行处理。同一个队列中的消息是先进先出的,这就足以实现消息的顺序性。
分区消费
虽然单消费者单队列可以完美保障消息的顺序性,但是其吞吐太低了。当需要多个消费者以提高处理速度时,可以使用分区消费。把一个队列分割成多个分区,每个分区由一个消费者处理,以此保障每个分区内消息的顺序性。例如最开始的修改资料这一业务,我们只需要保障每个用户的消息顺序性即可,因此我们可以使用分区消费来做(可以借助Spring-CLoud-Stream来实现)。
消息确认机制
使用手动消息确认机制,消费者在处理完一条消息后,显式地发送确认,这样RabbitMQ才会移除并继续发送下一条消息。
业务逻辑控制
在某些情况下,即使消息乱序到达,也可以在业务逻辑层面实现顺序控制。比如通过在消息中嵌入序列号,并在消费时根据这些信息来处理。
RabbitMQ本身并不能保证全局的严格顺序性。在实际开发中,根据具体的业务需求,可能需要结合多种策略来实现所需要的顺序保证。
相关文章:
【RabbitMQ】幂等性、顺序性
幂等性 概述 幂等性是数学和计算机科学中某些运算的性质,他们可以被多次应用,而不会改变初始应用的结果。RabbitMQ的幂等性则是指同一条消息,多次消费,对系统的影响是相同的。 一般消息中间件的消息传输保障分为三个层级&#…...
FFmpeg源码:avio_skip函数分析
AVIOContext结构体和其相关的函数分析: FFmpeg源码:avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析 FFmpeg源码:read_packet_wrapper、fill_buffer函数分析 FFmpeg源码:avio_read函数分析 FFmpeg源码ÿ…...

Llama 3.1 技术研究报告-6
6 推理 我们研究了两种主要技术,以使 Llama 3 405B 模型的推理⾼效:(1) 流⽔线并⾏和 (2) FP8 量化。我们已经公开发布了我们的 FP8 量化实现。 6.1 流⽔线并⾏ 当使⽤ BF16 数字表⽰模型参数时,Llama 3 405B 不适合在装有 8 个 Nvidia H1…...
更新日志-Python OS
这么久没更新全是因为这段时间的事情很多,只能一点一点的更新代码,不过好在,也是成功更新出来啦! 更新日志(2024/9/29) 代码全文更新,将所有的绝对路径替换为相对路径,这样在各位大…...

Chrome浏览器的C++内存管理技术揭秘
Chrome浏览器作为全球最流行的网络浏览器之一,其高效的内存管理技术功不可没。本文将深入探讨Chrome浏览器在C中的内存管理技术,并介绍如何通过调整网页加载时间、优化视频播放体验和解决谷歌浏览器占用CPU过高的问题来提升浏览器性能。 (本…...

Redis --- redis事务和分布式事务锁
redis事务基本实现 Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。 > MULTI OK > SET USER "Guide哥" QUEUED > GET USER QUEUED > EXEC 1) OK 2) "Guide哥"使用 MULTI命令后可以输入…...
SQL,将多对多的关联记录按行输出
数据库的Primary表和Secondary表有相同的结构,其中W、H、D是主键。Primary表:NameWHDPrimary item 1100500300Primary item 2100600300Primary item 3200500300Primary item 4100500300Primary item 5100600300Primary item 6200500300 Secondary表&…...

【SQL】筛选字符串与正则表达式
目录 语法 需求 示例 分析 代码 语法 SELECT column1, column2, ... FROM table_name WHERE condition; WHERE 子句用于指定过滤条件,以限制从数据库表中检索的数据。当你执行一个查询时,WHERE 子句允许你筛选出满足特定条件的记录。如果记录满…...

【Redis入门到精通五】Java如何像使用MySQL一样使用Redis(jedis安装及使用)
目录 Jedis 1.jedis是什么 2.jedis的安装配置 3.jedis的基础命令操作展示 1.set和get操作: 2.exists和del操作: 3.keys和type操作: 4. expire和ttl: Jedis Java 操作 redis 的客⼾端有很多,其中最知名的是 jedi…...

【 微信机器人+ AI 搭建】
摘要: 各种大模型已经出来好久了,各类app也已经玩腻了,接下来,就在考虑,怎么让大模型,利益最大化。 本人没有显著的家世,没有富婆包养,只能自己抽点时间,研究下技术&…...

VGG16网络介绍及代码撰写详解(总结1)
可以从本人以前的文章中可以看出作者以前从事的是嵌入式控制方面相关的工作,是一个机器视觉小白,之所以开始入门机器视觉的学习只要是一个idea,想把机器视觉与控制相融合未来做一点小东西。废话不多说开始正题。 摘要:本文是介绍V…...
多个excel表数据比对操作
多个excel表数据比对操作 本文主要使用两种方法进行比对,分别使用了openpyxl第三方库和pandas第三方库进行数据比对 两种方法优缺点: openpyxy: 优点:主要是处理xlsx的文件,里面方法简单,易懂 缺点:当数据量大的时候,速度很慢,之前我一条一条数据拿出来比较,两百多条…...
golang学习笔记32——哪些是用golang实现的热门框架和工具
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...

ZYNQ:开发环境搭建
资料下载 http://47.111.11.73/docs/boards/fpga/zdyz_qimxing(V2).html Vivado软件是什么? Vivado软件是Xilinx(赛灵思)公司推出的一款集成设计环境(IDE),主要用于FPGA(现场可编程门阵列&am…...
一步一步丰富生成式语言模型系统
以下是这套生成式语言模型解决任务的流程图概述: #mermaid-svg-sRHDSMUMV1utrg2F {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-sRHDSMUMV1utrg2F .error-icon{fill:#552222;}#mermaid-svg-sRHDSMUMV1u…...
Python中元组的常用方法
# 在Python中,元组(tuple)是一种不可变的序列类型,用于存储多个元素。元组的特点包括: # # 不可变性:一旦创建,元组的元素不能改变。这意味着不能添加、删除或修改元组中的元素。 # 可以包含任何…...

新版本Android Studio如何新建Java code工程
新版本Android Studio主推Kotlin,很多同学以为无法新建Java工程了,其实是可以的,如果要新建Java代码的Android工程,在New Project的时候需要选择Empty Views Activity,如图所示,gradle也建议选为build.grad…...
2024年世界职业院校技能大赛:全面升级的国际化职业技能竞赛
近日,中华人民共和国教育部发布了《2024年世界职业院校技能大赛实施方案》,宣布从2024年起将全国职业院校技能大赛升级为世界职业院校技能大赛。这一重大决策不仅标志着我国职业教育竞赛平台的全面国际化,更彰显了中国在全球职业教育领域的引领作用和战略眼光,具体内…...
前端vue相关常见面试题,包含MVVM、双向绑定原理、性能优化、vue2和vue3性能对比等
vue面试题 MVVM 概念 model view viewModel 本质上是mvc(程序分层开发思想) 将viewModel的状态和行为抽象化,viewmodel将视图ui和业务逻辑分开,去除model的数据,同时处理view中需要展示的内容和业务逻辑 view视图层 …...

生信初学者教程(十二):数据汇总
文章目录 介绍加载R包导入数据汇总表格输出结果总结介绍 在本教程中,汇总了三个肝细胞癌(HCC)的转录组数据集,分别是LIRI-JP,LIHC-US/TCGA-LIHC和GSE14520,以及一个HCC的单细胞数据集GSE149614的临床表型信息。这些数据集为科研人员提供了丰富的基因表达数据和相关的临床…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...