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

MQ保证消息的顺序性

在消息队列(MQ)中保证消息的顺序性是一个常见的需求,尤其是在需要严格按顺序处理业务逻辑的场景(例如:订单创建 → 支付 → 发货)。在这里插入图片描述

一、消息顺序性被破坏的原因

  1. 生产者异步/并行发送:消息可能以不同顺序到达MQ。
  2. MQ的分区/队列机制:消息被分散到不同分区或队列,不同队列的消费速度不一致。
  3. 消费者并行消费:多个消费者实例或线程同时处理消息,导致乱序。

二、保证消息顺序性的核心方案

核心原则将需要顺序处理的消息路由到同一个队列(或分区),并由单线程顺序消费

1. 生产者保证消息路由到同一队列
  • 业务标识路由:将同一业务标识(如订单ID、用户ID)的消息通过相同的路由键(如哈希取模)发送到同一个队列。

  • Kafka:为消息指定相同的 Key,相同 Key 的消息会进入同一个分区或者发送消息时将同一业务的消息指定到同一个分区partition

//指定分区 0
kafkaTemplate.send("kafka=topic", 0, "key-001", "value-0001");//相同业务key  key-001
kafkaTemplate.send("kafka=topic", "key-001", "value-0001");
  • RocketMQ:使用 MessageQueueSelector 自定义队列选择逻辑,确保同一业务的消息进入同一队列。
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {@Overridepublic MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {Integer id = (Integer) arg;int index = id % mqs.size();return mqs.get(index);}
}, orderId);
2. MQ服务端维护队列顺序
  • 分区/队列内有序:MQ需保证单个分区或队列内消息的存储和投递顺序与发送顺序一致。
  • 限制:Kafka分区、RocketMQ队列默认保证分区/队列内消息顺序。
3. 消费者单线程顺序消费
  • 单线程消费:消费者对同一队列的消息使用单线程处理,避免并发导致的乱序。
  • 示例
    • Kafka:每个分区仅由一个消费者线程处理,天生就是单线程的。
    • RocketMQ:使用 MessageListenerOrderly 监听器顺序消费。
  • 代码示例(RocketMQ消费者)
    consumer.registerMessageListener(new MessageListenerOrderly() {@Overridepublic ConsumeOrderlyStatus consumeMessage(List<MessageExt> messages, ConsumeOrderlyContext context) {// 单线程处理消息return ConsumeOrderlyStatus.SUCCESS;}
    });
    
4. 失败重试不破坏顺序
  • 顺序消费的重试机制:若某条消息消费失败,需阻塞后续消息处理,直到当前消息成功。
  • 示例:RocketMQ在顺序消费模式下,失败时会重试当前消息,后续消息需等待。

三、不同MQ的实现差异

消息队列顺序性支持关键配置
Kafka分区内顺序保证相同Key的消息发送到同一分区
RocketMQ队列内顺序保证(需使用顺序消息API)MessageListenerOrderly + 队列选择器
RabbitMQ无原生支持,需通过单队列+单消费者模拟顺序性单一队列 + 单消费者线程(synchronized

四、注意事项

  1. 性能与扩展性:顺序性会牺牲并行度,可通过增加队列/分区数量横向扩展(不同业务标识分散到不同队列)。
  2. 全局顺序性:需所有消息进入同一队列(如Kafka单分区),但会严重限制吞吐量,通常不建议。
  3. 业务设计:仅在必要场景(如订单链路)启用顺序性,其他场景尽量允许乱序。

五、总结

1. 保证消息顺序性的核心步骤:

  • . 生产者:按业务标识将消息路由到同一队列。
  • . MQ服务端:确保队列内消息存储有序。
  • . 消费者:单线程消费队列,失败时阻塞重试。
    通过合理设计业务标识和MQ配置,可以在分布式系统中高效实现局部顺序性,平衡一致性与性能。

2. 不同MQ如何选择

三种MQ相比较而言,RocketMQ更适合顺序消费的业务场景,总结如下:

  • . RabbitMQ需要设定交换机Exchange与队列Queue的绑定关系,并且一个队列只对应一个消费者Consumer才可以保证顺序消费,但是队列中的消息被消费者拉去后会从队列删除,如果消息消费失败,重试时会重新入队,消息的顺序就打乱了。
  • . Kafka虽然可以实现分区顺序消费但是在消息失败时,并不会锁住整个partition分区,该消息之后的消息还是会被消费,顺序也就打乱了,顺序消费的设计并没有RocketMQ那么完善。
  • . RocketMQ使用顺序发送,并结合队列选择器可以将同一业务消息发送到同一个队列,再结合MessageListenerOrderly监听器,保证生产者发送顺序和队列存储顺序以及消费者消费消息一致,并且消费失败时,会返回SUSPEND_CURRENT_QUEUE_A_MOMENT状态,阻塞队列一段时间(因为有队列锁),之后会从失败处开始再次消费。

RocketMQ顺序消费实现机制参考链接:https://blog.csdn.net/m0_71845127/article/details/145990210

相关文章:

MQ保证消息的顺序性

在消息队列&#xff08;MQ&#xff09;中保证消息的顺序性是一个常见的需求&#xff0c;尤其是在需要严格按顺序处理业务逻辑的场景&#xff08;例如&#xff1a;订单创建 → 支付 → 发货&#xff09;。 一、消息顺序性被破坏的原因 生产者异步/并行发送&#xff1a;消息可能…...

cmake、CMakeLists.txt、make、ninja

文章目录 一、概念0.cmake官网1.什么是cmake2.为什么使用cmake3.CMakeLists.txt 二、CMakeLists.txt语法&#xff1a;如何编写CMakeLists.txt&#xff0c;语法详解(0)语法基本原则(1)project关键字(2)set关键字(3)message关键字(4)add_executable关键字(5)add_subdirectory关键…...

数据结构与算法 计算机组成 八股

文章目录 数据结构与算法数组与链表的区别堆的操作红黑树定义及其原理 计算机组成int和uint的表示原码反码补码移码的定义&#xff1f;为什么用补码&#xff1f; 数据结构与算法 数组与链表的区别 堆的操作 红黑树定义及其原理 计算机组成 int和uint的表示 原码反码补码移…...

RoboBrain:从抽象到具体的机器人操作统一大脑模型

25年2月来自北大、北京智源、中科院自动化所等的论文“RoboBrain: A Unified Brain Model for Robotic Manipulation from Abstract to Concrete”。 目前的多模态大语言模型&#xff08;MLLM&#xff09; 缺少三项必备的机器人大脑能力&#xff1a;规划能力&#xff0c;将复杂…...

算法 之 前缀和 与 滑动窗口 与 背包问题 的差异(子数组之和为k问题)

文章目录 使用前缀和哈希表560.和为K的子数组525.连续数组2588.统计美丽子数组数目 子数组的定义是原来的数组当中连续的非空的序列&#xff0c;而我们的背包问题的选与不选的情况&#xff0c;对应的是这个非连续的情况,那么这种情况就要注意当然啦&#xff0c;对于线性的时间内…...

微电网协调控制器ACCU-100 分布式光伏 光储充一本化

安科瑞 华楠 18706163979 应用范围&#xff1a; 分布式光伏、微型风力发电、工商业储能、光储充一体化电站、微电网等领域。 主要功能&#xff1a; 数据采集&#xff1a;支持串口、以太网等多通道实时运行&#xff0c;满足各类风电与光伏逆变器、储能等 设备接入&#xff…...

IDEA入门及常用快捷键

IDEA是java常用的IDE。当run一个.java文件时&#xff0c;其实是经历了先编译为.class&#xff0c;再运行的过程。 在project文件夹中&#xff0c;out文件夹存储编译的.class文件&#xff0c;src文件夹存储.java代码文件。 设置自动导包 快捷键&#xff1a; 格式化快捷键&…...

electron打包结构了解

Electron 应用打包后的文件结构和内容取决于你使用的打包工具&#xff08;如 electron-builder、electron-packager 等&#xff09;以及目标操作系统&#xff08;Windows、macOS、Linux&#xff09;。以下是典型 Electron 应用打包后的文件结构和关键组成部分&#xff1a; 1. 基…...

03.06 QT

一、使用QSlider设计一个进度条&#xff0c;并让其通过线程自己动起来 程序代码&#xff1a; <1> Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QThread> #include "mythread.h"QT_BEGIN_NAMESPACE namespace Ui {…...

Python中的常用库

一、collections collections是 Python 标准库中的一个模块&#xff0c;提供了一些专门的容器数据类型&#xff0c;能够帮助你更高效地处理常见的数据结构操作。 1、Counter Counter 是一个字典的子类&#xff0c;用于计数可哈希对象。它会统计对象的出现次数&#xff0c;并…...

马尔科夫不等式和切比雪夫不等式

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 统计概率的利剑&#xff1a;掌…...

护照阅读器在汽车客运站流程中的应用

在汽车客运站的日常运营里&#xff0c;如何高效服务旅客、保障出行安全是工作重点。护照阅读器作为精准身份识别的得力工具&#xff0c;在客运站的多个关键流程&#xff0c;如自助购票、柜台购票、安检以及行李托运中&#xff0c;发挥着不可小觑的作用&#xff0c;有力地提升了…...

CentOS 7 安装Nginx-1.26.3

无论安装啥工具、首先认准了就是官网。Nginx Nginx官网下载安装包 Windows下载&#xff1a; http://nginx.org/download/nginx-1.26.3.zipLinxu下载 wget http://nginx.org/download/nginx-1.26.3.tar.gzLinux安装Nginx-1.26.3 安装之前先安装Nginx依赖包、自行选择 yum -y i…...

Unity 使用NGUI制作无限滑动列表

原理&#xff1a; 复用几个子物体&#xff0c;通过子物体的循环移动实现&#xff0c;如下图 在第一个子物体滑动到超出一定数值时&#xff0c;使其放到最下方 --------------------------------------------------------------》 然后不停的循环往复&#xff0c;向下滑动也是这…...

linux中断调用流程(arm)

文章目录 ARM架构下Linux中断处理全流程解析&#xff1a;从硬件触发到驱动调用 ⚡**一、中断触发与硬件层响应** &#x1f50c;**1. 设备触发中断** &#x1f4e1; **二、CPU阶段&#xff1a;异常入口与上下文处理** &#x1f5a5;️**1. 异常模式切换** &#x1f504;**2. 跳转…...

基于Matlab的多目标粒子群优化

在复杂系统的设计、决策与优化问题中&#xff0c;常常需要同时兼顾多个相互冲突的目标&#xff0c;多目标粒子群优化&#xff08;MOPSO&#xff09;算法应运而生&#xff0c;作为群体智能优化算法家族中的重要成员&#xff0c;它为解决此类棘手难题提供了高效且富有创新性的解决…...

【网络安全】——协议逆向与频繁序列提取:从流量中解码未知协议

目录 引言 一、为什么要结合频繁序列提取&#xff1f; 二、四步融合分析法 步骤1&#xff1a;原始流量采集与预处理 步骤2&#xff1a;多粒度序列模式挖掘 层1&#xff1a;单包内字节级频繁项 层2&#xff1a;跨数据包的行为序列 步骤3&#xff1a;关键字段定位与结构假…...

CSS 中等比例缩放的演变:从传统技巧到 aspect-ratio 属性

CSS 中等比例缩放的演变&#xff1a;从传统技巧到 aspect-ratio 属性 在响应式网页设计和多设备兼容成为主流的今天&#xff0c;如何实现元素的等比例缩放成为前端开发中一个重要的课题。无论是图片、视频还是其他容器&#xff0c;都常常需要保持固定的宽高比&#xff0c;以便…...

系统架构设计师—计算机基础篇—进度管理

文章目录 基本概念进程的特征进程的状态前趋图 进程的通信进程的互斥做题方法 进程的同步PV操作做题方法 基本概念 进程的特征 进程通常由程序、数据集合、进程控制块PCB组成。 PCB是一种数据结构&#xff0c;是进程存在的唯一标识。 组织方式说明线性方式把所有PCB组织在一…...

初始提示词(Prompting)

理解LLM架构 在自然语言处理领域&#xff0c;LLM&#xff08;Large Memory Language Model&#xff0c;大型记忆语言模型&#xff09;架构代表了最前沿的技术。它结合了存储和检索外部知识的能力以及大规模语言模型的强大实力。 LLM架构由外部记忆模块、注意力机制和语…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...