【RabbitMQ】当队列中消息数量超过最大长度的淘汰策略
【RabbitMQ】当队列中消息数量超过最大长度的淘汰策略
说明
最近在研究RabbitMQ如何实现延时队列时发现消息进入死信队列的情况之一就是当消息数量超过队列设置的最大长度时会被丢入死信队列,看到这时我就产生了一个疑问,到底是最后插入的消息还是最早插入的消息会被丢入死信队列呢?遗憾的是看了几篇博客都是模棱两可的答案,还有的说超过数量后该消息会被放入死信队列,看完之后还是对这个问题将信将疑。所以我决定去探究一下正确答案
答案
遇事不决肯定是先看官方文档最靠谱啦,在官网中扒拉了半天终于找到说明这个问题的页面了,就是上面引用的链接,重点如下:

翻译过来就是:在RabbitMQ中,当消息的数量或大小达到限制后,默认的操作是删除最旧的消息或将最旧的消息放入死信队列,这取决于该队列是否配置了死信队列。 我们可以通过使用overflow配置指定的处理策略,如果overflow被设置为reject-publish或reject-publish-dlx,那么会将最新插入的消息丢弃。如果该队列开启了confirm机制,发布者会收到nack的信息,如果一个消息被路由到多个队列,只要其中一个队列拒绝发布者就会收到nack消息,但是没被拒绝的队列可以正确接收到消息。reject-publish和reject-publish-dlx的区别是后者还会将拒绝的消息放入死信队列。
验证
下面我们使用demo来验证一下各个策略的现象
默认策略(drop-head)
- application.yml配置如下:
rabbitmq:
host: 127.0.0.1
port: 5672
username: username
password: password
virtual-host: /test
publisher-confirm-type: correlated # 配置启用confirm机制
- 使用RabbitMQConfig创建业务队列和对应死信队列
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@Configuration
public class RabbitMQConfig {
public static final String DELAY_EXCHANGE_NAME = "delay.business.exchange";
public static final String DELAY_QUEUE_NAME = "delay.business.queue";
public static final String DELAY_QUEUE_ROUTING_KEY = "delay.business.queue.routingKey";
public static final String DEAD_LETTER_EXCHANGE_NAME = "dead.letter.exchange";
public static final String DEAD_LETTER_QUEUE_NAME = "dead.letter.queue";
public static final String DEAD_LETTER_QUEUE_ROUTING_KEY = "dead.letter.queue.routingKey";
// 声明延迟队列交换机
@Bean("delayExchange")
public DirectExchange delayExchange(){
return new DirectExchange(DELAY_EXCHANGE_NAME);
}
// 声明死信队列交换机
@Bean("deadLetterExchange")
public DirectExchange deadLetterExchange(){
return new DirectExchange(DEAD_LETTER_EXCHANGE_NAME);
}
// 声明延时队列
@Bean("delayQueue")
public Queue delayQueue(){
HashMap<String, Object> map = new HashMap<>();
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
map.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE_NAME);
// x-dead-letter-routing-key 这里声明当前队列的死信路由key
map.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUE_ROUTING_KEY);
// 设置该队列最大消息数
map.put("x-max-length", 10);
map.put("x-overflow", "reject-publish");
return QueueBuilder.durable(DELAY_QUEUE_NAME).withArguments(map).build();
}
// 声明死信队列
@Bean("deadLetterQueue")
public Queue deadLetterQueue(){
return new Queue(DEAD_LETTER_QUEUE_NAME);
}
// 声明延时队列的绑定关系
@Bean
public Binding delayBinding(@Qualifier("delayExchange") DirectExchange directExchange,
@Qualifier("delayQueue") Queue queue){
return BindingBuilder.bind(queue).to(directExchange).with(DELAY_QUEUE_ROUTING_KEY);
}
// 声明死信队列的绑定关系
@Bean
public Binding deadLetterBinding(@Qualifier("deadLetterExchange") DirectExchange directExchange,
@Qualifier("deadLetterQueue") Queue queue){
return BindingBuilder.bind(queue).to(directExchange).with(DEAD_LETTER_QUEUE_ROUTING_KEY);
}
}
注意,这里我们并没有设置overflow参数,所以采用的是默认配置
3. 创建消费者监听死信队列
import com.rabbitmq.client.Channel;
import com.whs.edws.config.RabbitMQConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component
public class MaxLengthConsumer {
@RabbitListener(queues = RabbitMQConfig.DEAD_LETTER_QUEUE_NAME)
public void receive(Message message, Channel channel) throws IOException {
String s = new String(message.getBody());
log.info("死信队列消费者接收到消息:" + s);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
- 创建测试方法发送消息
@Test
void maxLengthTestPublish(){
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
* @param correlationData 相关配置信息
* @param ack 消息队列是否成功收到消息
* @param cause 错误原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
logger.info("消息发送成功:" + correlationData.getId());
} else {
logger.error("消息发送失败:" + correlationData.getId());
logger.error("错误原因:" + cause);
}
}
});
for (int i = 0; i < 11; i++) {
CorrelationData correlationData = new CorrelationData();
correlationData.setId(String.valueOf(i));
rabbitTemplate.convertAndSend(RabbitMQConfig.DELAY_EXCHANGE_NAME, RabbitMQConfig.DELAY_QUEUE_ROUTING_KEY, String.valueOf(i), correlationData);
}
}
- 运行结果
看上面的代码可知,我们设置了队列大小为10,但是我们向队列发送了11条消息,最后日志打印如下:
2023-07-18 02:37:52.941 INFO 24308 --- [ntContainer#1-1] com.edws.rabbitmq.MaxLengthConsumer : 死信队列消费者接收到消息:0
和官方文档说的一样,默认最旧的一条消息被放入死信队列
reject-publish策略
reject-publish策略的验证代码只需在默认策略的基础上加上配置即可,我们在定义队列的时候加上配置
// 指定超过队列长度后的策略
map.put("x-overflow", "reject-publish");
执行方法,打印的结果为:
2023-07-18 02:45:07.242 INFO 22328 --- [nectionFactory2] o.s.amqp.rabbit.core.RabbitTemplate : 消息发送失败:10
2023-07-18 02:45:07.242 INFO 22328 --- [nectionFactory2] o.s.amqp.rabbit.core.RabbitTemplate : 错误原因:null
通过日志可以看到,最新插入的消息被丢弃了。至于cause为什么是null,我没找到原因,如果了解的朋友可以在评论里讨论一下
reject-publish-dlx策略
reject-publish-dlx策略的代码也是只需要在默认代码中加一行配置即可
// 指定超过队列长度后的策略
map.put("x-overflow", "reject-publish-dlx");
打印结果如下:
2023-07-18 02:49:13.246 INFO 10488 --- [nectionFactory2] o.s.amqp.rabbit.core.RabbitTemplate : 消息发送失败:10
2023-07-18 02:49:13.246 INFO 10488 --- [nectionFactory2] o.s.amqp.rabbit.core.RabbitTemplate : 错误原因:null
2023-07-18 02:49:13.252 INFO 10488 --- [ntContainer#1-1] com.whs.edws.rabbitmq.MaxLengthConsumer : 死信队列消费者接收到消息:10
通过日志可以看出,最新的一条消息被拒绝且被放入死信队列
【RabbitMQ】当队列中消息数量超过最大长度的淘汰策略的更多相关文章
- rabbitmq队列中消息过期配置
最近公司某个行情推送的rabbitmq服务器由于客户端异常导致rabbitmq队列中消息快速堆积,还曾导致过内存积压导致rabbitmq客户端被block的情况.考虑到行情信息从业务上来说可以丢失部分 ...
- RabbitMQ镜像模式双节点部署时故障转移过程中队列中消息的状态
场景 现有节点Node1和Node2,建立Exchange:yu.exchange,创建队列yu1.queue镜像队列master位于Node1,yu2.queue镜像队列位于Node2,使用topi ...
- RabbitMQ获取队列的消息数目
使用RabbitMQ,业务需求,想要知道队列中还有多少待消费待数据. 方式一: @Value("${spring.rabbitmq.host}") private String h ...
- 《剑指offer》数组中出现次数超过数组长度一半的数字
题目: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.如 ...
- 【剑指offer】数组中出现次数超过数组长度一半的数字,C++实现
原创博文,转载请注明出处! # 题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过 ...
- 找出整数数组中出现次数超过数组长度一半的元素(Java)
Question:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字 package com.study.zhipengs.test; import java.util.Arrays; im ...
- activemq读取剩余消息队列中消息的数量
先上原文链接: http://blog.csdn.net/bodybo/article/details/5647968 ActiveMQ在C#中的应用 ActiveMQ是个好东东,不必多说.Acti ...
- RabbitMQ 延迟队列,消息延迟推送
目录 应用场景 消息延迟推送的实现 测试结果 应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给 ...
- 显示推送数据到mq成功,但是mq管理器中消息数量没增长
看服务器上的mq配置,看看mq_log,是不是存储满了?
- 【RabbitMQ】一文带你搞定RabbitMQ死信队列
本文口味:爆炒鱿鱼 预计阅读:15分钟 一.说明 RabbitMQ是流行的开源消息队列系统,使用erlang语言开发,由于其社区活跃度高,维护更新较快,性能稳定,深得很多企业的欢心(当然,也包括我 ...
随机推荐
- css盒子水平垂直居中的几种方式
第一种:son盒子中定位的上下左右全部为0,然后margin:auto 1 <!DOCTYPE html> 2 <html lang="en"> 3 < ...
- 设置Windows主机的浏览器为wls2的默认浏览器
这里以Chrome为例. 1. 准备工作 wsl是可以使用Windows主机上安装的exe程序,出于安全考虑,默认情况下改功能是无法使用.要使用的话,终端需要以管理员权限启动. 我这里以Windows ...
- Java实现平衡二叉搜索树(AVL树)
上一篇实现了二叉搜索树,本章对二叉搜索树进行改造使之成为平衡二叉搜索树(Balanced Binary Search Tree). 不平衡的二叉搜索树在极端情况下很容易退变成链表,与新增/删除/查找时 ...
- 第139篇:JS数组常用方法(map(),reduce(),foreach())
好家伙,本篇为MDN文档数组方法的学习笔记 Array.prototype.reduce() - JavaScript | MDN (mozilla.org) 数组方法这块的知识缺了,补一下 1. ...
- Node + Express 后台开发 —— 登录标识
登录标识 系统通常只有登录成功后才能访问,而 http 是无状态的.倘若直接请求需要登录才可访问的接口,假如后端反复查询数据库,而且每个请求还得带上用户名和密码,这都是不很好. 作为前端,我们听过 c ...
- 用Python语言进行时间序列ARIMA模型分析
应用时间序列 时间序列分析是一种重要的数据分析方法,应用广泛.以下列举了几个时间序列分析的应用场景: 1.经济预测:时间序列分析可以用来分析经济数据,预测未来经济趋势和走向.例如,利用历史股市数据和经 ...
- 自创简易CSS Tab 选项卡
前段时间我注册了 w3c.run域名,打算做一个W3C相关技术在线试验工具.没错,就是在线编写html.css.js代码然后在线运行,查看效果. 在设计首页时,我打算首页提供三个代码编辑器,介于界面大 ...
- Docker网络类型
Docker网络类型 目录 Docker网络类型 跟VMware对比 VMware Docker route命令 Docker的网络工作模式 Bridge模式 host模式 Container模式 n ...
- 2021-12-31:给定一个arr,里面的数字都是0~9, 你可以随意使用arr中的数字,哪怕打乱顺序也行, 请拼出一个能被3整除的,最大的数字,用str形式返回。 来自去哪儿网。
2021-12-31:给定一个arr,里面的数字都是0~9, 你可以随意使用arr中的数字,哪怕打乱顺序也行, 请拼出一个能被3整除的,最大的数字,用str形式返回. 来自去哪儿网. 答案2021-1 ...
- Git开发、发布、缺陷分离模型概述(支持master/develop/feature/release/hotfix类型分支)
Git是什么? Git是一种分布式版本控制系统,它可以记录文件的修改历史和版本变化,并可以支持多人协同开发.Git最初是由Linux开发者Linus Torvalds创建的,它具有高效.灵活.稳定等优 ...