RabbitMQ - 消息堆积问题的最佳解决方案?惰性队列

news2024/12/26 1:15:38

目录

一、惰性队列

1.1、消息堆积问题

1.2、消息堆积问题的解决方法

从消费者的角度:

从队列的角度:

1.3、引入惰性队列

1.3.1、什么是惰性队列

1.3.2、惰性队列的使用

1.3.3、效果演示


一、惰性队列


1.1、消息堆积问题

当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息到达上限.

这就像是有一个蓄水池,一边往里注水,一边向外排水,但是注水速度比排水快,因此这个水池最终就会填满.

接着,最早收到的消息,就可能成为死信,默认情况下会把死信丢弃,丢弃了之后队列就有了空间,就可以新消息进入队列.

1.2、消息堆积问题的解决方法

从消费者的角度:

1. 增加更多的消费者,调高消费速度.

如果说现在只有单个消费者,处理速度是 100ms 一个消息,那么如果有三个消费者,理论上就处理速度就是 300ms 一个消息.

2.在消费者内开启一个线程池,每当一个消息过来了,就交给一个线程去处理,那么当前这个消费者内部处理消息的速度就加快了.

但是,这个方法有一个限制,就是如果消息特别多的情况下,你是不是就需要分配很多线程.  线程越多,对 cpu 来讲也是一种浪费,因为 cpu 需要在多个线程之间做上下文切换,所以这个方案比较适合消息处理业务比较耗时的情况,开多个线程,让 cpu 并行处理.

从队列的角度:

3. 扩大队列容积,提高堆积上限.

就像一个蓄水池,我把这个水池搞的像黄河那么大,你再往里进水,啥时候才能填满呢~

前两种方法我们已经是比较的熟悉的了,但是最后扩大队列容积,具体该如何实现呢?

惰性队列就可以用来解决这个问题~

1.3、引入惰性队列

1.3.1、什么是惰性队列

对于传统的队列来讲,如果没有开启消息持久化,所有接收到的消息都是放在内存里面的,目的就是为了加快消息投递的速度,这也是 RabbitMQ 的一个很优势——响应速度快.

但是他也带来了一个问题,RabbitMQ 设置了一个内存预警值(内存存储的上限,默认是 40%),如果在消息堆积的情况下,很容易就到达这个预警值,此时,RabbitMQ 就会处于一个暂停状态,会阻止生产者投递消息进来,然后把内存中的一部分消息清理出来,刷出到磁盘中,这动作也叫 “page out” .  进而导致 mq 的并发能力,忽高忽低,性能不稳定(每次page out 都会比较耗时,停顿一段时间).

而惰性队列,就是是专门用来处理消息堆积问题的~

他有以下三个特点:

1. 收到的消息会直接写入磁盘,而非内存,也因此很难触发 mq 的内存预警,几乎不会出现 page out 的情况.

2. 消费者消费惰性队列的消息,也需要先从磁盘中读取并加载到内存中.  实际上这也会使延迟稍微高一点,毕竟磁盘的性能和内存还是有很大差距的,但是也在可以接收到范围内.

3. 支持数百万的消息存储,这也是因为他是磁盘存储(空间非常大).

1.3.2、惰性队列的使用

设置一个队列为 惰性队列,有以下三种方式:

1. 在 RabbitMQ Managerment 中,我们只需要在声明队列的时候,指定 x-queue-mode 属性为 lazy 即可.

2. 用 SpringAMQP 声明惰性队列,@Bean 方式如下:

@Configuration
public class LazyConfig {

    @Bean
    public Queue lazyQueue() {
        return QueueBuilder
                .durable("lazy.queue")
                .lazy() //开启 x-queue-mode 属性为 lazy
                .build();
    }

}

3. 用 SpringAMQP 声明惰性队列,注解方式如下:

    @RabbitListener(queuesToDeclare = @Queue(
        name = "lazy.queue",
            durable = "true",
            arguments = @Argument(name = "x-queue-mode", value = "lazy")
    ))
    public void listenLazyQueue(String msg) {
        log.info("消费者接收到了惰性队列的消息! msg=" + msg);
    }

1.3.3、效果演示

a)使用 @Bean 声明一个普通队列和一个惰性队列,来对比效果.

@Configuration
public class LazyConfig {

    @Bean
    public Queue lazyQueue() {
        return QueueBuilder
                .durable("lazy.queue")
                .lazy() //开启 x-queue-mode 属性为 lazy
                .build();
    }

    @Bean
    public Queue normalQueue() {
        return QueueBuilder
                .durable("normal.queue")
                .build();
    }

}

b)使用两个生产者,分别向两个队列中发送 100000 消息.

    @Test
    public void testLazyMessage() {
        for(int i = 0; i < 1000000; i++) {
            //1.准备消息
            Message message = MessageBuilder.withBody("hello lazy message".getBytes())
                    .setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT)
                    .build();
            //2.发送消息
            rabbitTemplate.convertAndSend("lazy.queue", message);
        }
    }

    @Test
    public void testNormalMessage() {
        for(int i = 0; i < 1000000; i++) {
            //1.准备消息
            Message message = MessageBuilder.withBody("hello normal message".getBytes())
                    .setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT)
                    .build();
            //2.发送消息
            rabbitTemplate.convertAndSend("normal.queue", message);
        }
    }

普通队列情况如下:

普通队列每次往 memory 中写入一定量的数据后,暂停一段时间,向磁盘写数据(page out).

lazy 队列情况如下:

lazy 一直都往磁盘上写数据,所以 total 等于 paged out.

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

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

相关文章

leetcodeTop100(21) 相交链表

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&#xff0c;链表必须 保持其原始结构 。 双链表…

1:DDD入门

产品代码都给你看了&#xff0c;可别再说不会DDD&#xff08;一&#xff09;&#xff1a;DDD入门 # 这是一个讲解DDD落地的文章系列&#xff0c;作者是《实现领域驱动设计》的译者滕云。本文章系列以一个真实的并已成功上线的软件项目——码如云&#xff08;https://www.mryqr…

【车载开发系列】UDS中Bootloader实现原理

【车载开发系列】UDS中Bootloader实现原理 【车载开发系列】UDS中Bootloader实现原理 【车载开发系列】UDS中Bootloader实现原理一. Bootloader存放位置二. BootLoader的安全机制1&#xff09;安全访问2&#xff09;刷新预条件3&#xff09;完整性校验4&#xff09;一致性检查5…

NextJS 引入 Ant-Design 样式闪烁问题

按照这里给的样例&#xff0c;抽出关键代码即可 步骤&#xff1a; 安装包&#xff1a; npm i ant-design/static-style-extract引入这俩文件 genAntdCss.tsx: 会帮我们生成 ./public/antd.min.css // src/scripts/genAntdCss.tsximport { extractStyle } from "ant-d…

从锁的类别角度讲,MySQL都有哪些锁

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

2024北京老博会,CBIAIE中国北京国际老年产业博览会

2024第11届中国&#xff08;北京&#xff09;国际老年产业博览会&#xff0c;将于4月10-12日盛大举行 2024第11届中国&#xff08;北京&#xff09;国际老年产业博览会&#xff08;CBIAIE北京老博会&#xff09; The 2024 eleventh China (Beijing) International Aged Indust…

【动手学深度学习-Pytorch版】长短期记忆网络LSTM

LSTM参数说明以及网络架构图 PS&#xff1a;时间仓促&#xff0c;有空补充内容~ LSTM从零开始实现 """ 遗忘门&#xff1a;相当于一个橡皮擦&#xff0c;决定保留昨天的哪些信息 输入门&#xff1a;相当于一个铅笔&#xff0c;再次根据昨天的记忆和今天的输…

【数据结构】list.h 详细使用教程 -- 附带例子代码

目录 一、概述二、详细使用步骤✨2.1 定义结构体包含 struct list_head 成员✨2.2 初始化链表头结点&#xff1a;INIT_LIST_HEAD✨2.3 添加结点&#xff1a;list_add、list_add_tail✨2.4 遍历链表&#xff1a;list_for_each、list_for_each_safe、list_for_each_entry✨2.5 获…

java double类型 向上取整,向下取整,四舍五入

向上取整&#xff1a;Math.ceil(double a) 向下取整&#xff1a;Math.floor(double a) 四舍五入取整&#xff1a;Math.round(double a) 直接取整数&#xff1a;intValue() public static void main(String[] args) {Double number 5.3;Double number1 5.8;//向上取整Doubl…

UE5 虚幻引擎 如何使用构造脚本(Construction Script)? 构造脚本的奥秘!

目录 1 构造脚本&#xff08;Construction Script&#xff09;1.1 介绍1.2 案例1&#xff1a;利用样条组件程序化生成树木1.2 案例2&#xff1a;利用样条组件和样条网格体组件程序化生成道路 1 构造脚本&#xff08;Construction Script&#xff09; 1.1 介绍 问题&#xff1a…

leetcode top100(20) 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,2…

腾讯mini项目-【指标监控服务重构】2023-08-24

今日已办 Jeager 功能 监控分布式工作流程并排除故障识别性能瓶颈追踪根本原因分析服务依赖关系 部署 部署 Deployment — Jaeger documentation (jaegertracing.io) 支持 clickhouse jaegertracing/jaeger-clickhouse: Jaeger ClickHouse storage plugin implementation …

Java8实战-总结34

Java8实战-总结34 重构、测试和调试使用 Lambda 重构面向对象的设计模式观察者模式责任链模式 重构、测试和调试 使用 Lambda 重构面向对象的设计模式 观察者模式 观察者模式是一种比较常见的方案&#xff0c;某些事件发生时&#xff08;比如状态转变&#xff09;&#xff0…

Java之转换流的详细解析

2. 转换流 2.1 字符编码和字符集 字符编码 计算机中储存的信息都是用二进制数表示的&#xff0c;而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则&#xff0c;将字符存储到计算机中&#xff0c;称为编码 。反之&#xff0c;将…

docker容器安装MongoDB数据库

一&#xff1a;MongoDB数据库 1.1 简介 MongoDB是一个开源、高性能、无模式的文档型数据库&#xff0c;当初的设计就是用于简化开发和方便扩展&#xff0c;是NoSQL数据库产品中的一种。是最 像关系型数据库&#xff08;MySQL&#xff09;的非关系型数据库。 它支持的数据结构…

封装一个高级查询组件

封装一个高级查询组件 背景一&#xff0c;前端相关代码二&#xff0c;后端相关代码三&#xff0c;呈现效果总结 背景 业务有个按照自定义选择组合查询条件&#xff0c;保存下来每次查询的时候使用的需求。查了一下项目里的代码没有现成的组件可以用&#xff0c;于是封装了一个 …

腾讯mini项目-【指标监控服务重构】2023-08-29

今日已办 Collector 指标聚合 由于没有找到 Prometheus 官方提供的可以聚合指定时间区间内的聚合函数&#xff0c;所以自己对接Prometheus的api来聚合指定容器的cpu_avg、cpu_99th、mem_avg 实现成功后对接小组成员测试完提供的时间序列和相关容器&#xff0c;将数据记录在表格…

相机One Shot标定

1 原理说明 原理部分网上其他文章[1][2]也已经说的比较明白了&#xff0c;这里不再赘述。 2 总体流程 参考论文作者开源的Matlab代码[3]和github上的C代码[4]进行说明&#xff08;不得不说还是Matlab代码更优雅&#xff09; 论文方法总体分两部&#xff0c;第一部是在画面中找…

李宏毅hw-9:Explainable ML

——欲速则不达&#xff0c;我已经很幸运了&#xff0c;只要珍惜这份幸运就好了&#xff0c;不必患得患失&#xff0c;慢慢来。 ----查漏补缺&#xff1a; 1.关于这个os.listdir的使用 2.从‘num_文件名.jpg’中提取出数值&#xff1a; 3.slic图像分割标记函数的作用&#xf…

【音视频流媒体】4、摄像头:分辨率、光圈|快门|感光度、焦距

文章目录 一、摄像头分辨率二、光圈、快门、感光度2.1 光圈2.1.1 外观2.1.2 光圈在相机中如何表示的2.1.3 对拍照的影响2.1.4 如何选择合适的光圈2.1.5 光圈在相机中如何设置 2.2 快门2.2.1 外观2.2.2 快门在相机中的表示2.2.3 快门对于拍照有什么影响2.2.4 选择合适的快门2.2.…