当前位置: 首页 > news >正文

【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源码&#xff…...

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的临床表型信息。这些数据集为科研人员提供了丰富的基因表达数据和相关的临床…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

线程同步:确保多线程程序的安全与高效!

全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

Pydantic + Function Calling的结合

1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...

【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解

一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...

Mysql故障排插与环境优化

前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...