RabbitMq--- 惰性队列

news/2024/10/23 5:44:15/

前言

消息堆积是Mq消费时常见的问题,这里我们展开说一下消息堆积的原因,以及RabbitMq 中是如何解决这个问题的。

1. 消息堆积问题

当生产者发送消息时的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。最早收到的消息,可能会成为死信,会被丢弃,这就是消息堆积问题。
在这里插入图片描述
解决消息堆积有三种思路:

  • 增加更多的消费者,提高消费速度
  • 在消费者内开启线程池加快消息处理速度
  • 扩大队列容积,提高堆积上限

RabbitMq 中解决消息堆积的思路是扩大队列容积,但是它把消息存储从内存中剥离出来,使用了磁盘。

2. 惰性队列

在 RabbitMq 的 3.6.0 版本开始,就增加了 Lazy Queues 的概念,也就是惰性队列,惰性队列的特征如下:

  • 接收到消息后直接存入磁盘而非内存
  • 消费者消费消息时才会从磁盘中读取并加载到内存
  • 支持百万条的消息存储

2.1 命令行设置

设置一个队列为惰性队列,只需要在声明队列时,指定 x-queue-mode 属性为 lazy 即可。可以通过命令将一个运行中的队列修改为惰性队列

rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy"}' --apply-to queues  
  • rabbitmqctl: RabbitMq 的命令行工具
  • set_policy: 添加一个策略
  • Lazy: 策略名称,可以自定义
  • ^lazy-queue$: 用正则表达式匹配队列的名字
  • {“queue-mode”:“lazy”}: 设置队列模式位 lazy 模式
  • –apply-to queues: 策略的作用对象,是所有的队列

而 SpringAMQP 中声明惰性队列分为两种方式, 一种是@Bean 的方式,一种是基于注解的方式

2.2 基于@Bean 的方式

使用 .lazy( ) 开启x-queue-mode为lazy

import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/** 惰性队列配置 */
@Configuration
public class LazyConfig {/** 惰性队列 - 增加了.lazy()属性 */@Beanpublic Queue lazyQueue() {return QueueBuilder.durable("lazy.queue").lazy() // 开启x-queue-mode为lazy.build();}/** 正常队列 */@Beanpublic Queue normalQueue(){return QueueBuilder.durable("normal.queue").build();}
}

2.3 基于注解方式:

在消费者端的消息监听中新增方法
使用 @Argument 来标注使用参数的key 和对应参数的值 value

@RabbitListener(queuesToDeclare = @Queue(name = "lazy.queue",durable = "true",arguments = @Argument(name = "x-queue-mode", value = "lazy")
))
public void listenLazyQueue(String msg) {log.info("接收到 lazy.queue 的消息:{}", msg);
}

3. 案例测试

这里对正常队列和惰性队列进行十万条数据的测试,启动consumer服务,在publisher服务的SpringAmqpTest类中新增下列两个方法:

/** 测试惰性队列 */
@Test
public void testLazyQueue() throws InterruptedException {// 模拟发送十万条数据long b = System.nanoTime();for (int i = 0; i < 1000000; i++) {// 1.准备消息Message message = MessageBuilder.withBody("hello, LazyQueue".getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT) // 改成非持久化,可以看一下LazyQueue的效果.build();// 2.发送消息rabbitTemplate.convertAndSend("lazy.queue", message);}long e = System.nanoTime();System.out.println(e - b);
}/** 测试正常队列 */
@Test
public void testNormalQueue() throws InterruptedException {// 模拟发送十万条数据long b = System.nanoTime();for (int i = 0; i < 1000000; i++) {// 1.准备消息Message message = MessageBuilder.withBody("hello, Spring".getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT) // 改成非持久化,可以看一下正常队列的效果.build();// 2.发送消息rabbitTemplate.convertAndSend("normal.queue", message);}long e = System.nanoTime();System.out.println(e - b);
}

RabbitMQ控制台队列的数据变化:

  • 初始化:
    在这里插入图片描述

  • 运行两个生产者方法后,看一下两个队列总览
    在这里插入图片描述

  • 惰性队列数据变化 (全部一进来就会存储到磁盘,内存中只有需要消费的)
    在这里插入图片描述

  • 正常队列数据变化:
    而正常队列都在内存中(这里是没有开启持久化的情况)

    在这里插入图片描述

4. 总结

消息堆积问题的解决方案?

  • 队列上绑定多个消费者,提高消费速度
  • 给消费者开启线程池,提高消费速度
  • 使用惰性队列,可以在 mq 中保存更多消息

惰性队列的优点有哪些?

  • 基于磁盘存储,消息上限高
  • 没有间隙性的 page-out, 性能比较稳定

惰性队列的缺点有哪些?

  • 基于磁盘存储,消息时效性会降低
  • 性能受限于磁盘的 IO

http://www.ppmy.cn/news/87066.html

相关文章

【JavaSE】Java基础语法(十二):ArrayList

文章目录 1. ArrayList的构造方法和添加方法2. ArrayList类常用方法3. ArrayList存储学生对象并遍历 集合和数组的区别 : 共同点&#xff1a;都是存储数据的容器不同点&#xff1a;数组的容量是固定的&#xff0c;集合的容量是可变的 1. ArrayList的构造方法和添加方法 ArrayL…

神策「数据闭环解决方案」重磅上线,3 大方向助推业务起飞

在通过数据驱动业务增长的落地实践中&#xff0c;企业大多面临以下困扰&#xff1a; 数据源多且杂乱&#xff0c;该如何从 0 开始积累数据助力业务决策&#xff1f; 如何借助数据的力量&#xff0c;洞察业务关键增长点&#xff1f; 如何提升运营效率&#xff1f;怎样提高用户的…

jQuery-使用attr和prop操作属性

<!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <title>使用attr和prop操作属性</title> <script type"text/javascript&qu…

STM32——关于GPIO讲解及标准库应用(基础篇)

简介&#xff1a; STM32是一系列基于ARM Cortex-M内核的32位微控制器。该系列微控制器广泛应用于计算机、通讯、工业自动化、消费电子、汽车电子、医疗仪器及家庭电器等领域。该系列控制器具有高性能、低功耗、智能化等特点。其中&#xff0c;GPIO就是STM32控制器中的一…

final域的内存语义

final域的重排序规则 对于final域&#xff0c;编译器和处理器要遵守两个重排序规则。1&#xff09;在构造函数内对一个final域的写入&#xff0c;与随后把这个被构造对象的引用赋值给一个引用变量&#xff0c;这两个操作之间不能重排序。2&#xff09;初次读一个包含final域的…

阿拉德手游服务端Centos搭建教程

阿拉德手游服务端Centos搭建教程 大家好我是艾西&#xff0c;又有几天没有更新文章了。这几天看了看还是有不少人对手游感兴趣&#xff0c;今天给大家分享一款早些年大火的pc游戏&#xff0c;现在也有手游了“阿拉德”。 你是否还记得DNF&#xff0c;一天你不小心救了赛丽亚&a…

扩展磁盘大小

此虚拟机之前硬盘大小为40G&#xff0c;需扩展为500G 1.虚拟机设置中&#xff0c;扩展硬盘大小为500G 2.启动此虚拟机&#xff0c;查看当前磁盘大小 3.查看磁盘情况 可查看到当前磁盘大小总共537G&#xff0c;实际使用37G 4.对磁盘分区 刷新分区 查看磁盘情况&#xff0c;可查…

编程的实践理论 第二章 基础的数据结构

第二章 基础的数据结构 一个数据结构是一个数据的集合。数据可能是二进制的值,数字 字符,或者是数据结构。我们认为的基本的结构化的类型是 打包和索引化。这两种结构提供了四种基本的数据结构。 非打包的,非索引化的是束, 打包的,非索引化的是集合 非打包的,索引化的是…