系列十四、死信队列

一、死信队列

1.1、概述

        上一篇介绍了RocketMQ中的消息重试机制,我们可以知道当消息重试了一定的次数后,将不再继续重试,那么这个未被消费者成功消费的消息去了哪里了?带着这个问题,我们开始本章的学习。死信队列是一种特殊的队列,专门用于存放因消费者端无法正常消费的消息,例如上一篇文章中介绍中的消息由于无法成功被消费,最终进入了死信队列,具体进入的死信队列如下:

1.2、死信队列的Topic

        死信队列的Topic是由以下两部分组成的,格式为:%DLQ%${消费者组},如:%DLQ%retry-consumer-group

1.3、如何查看死信队列中的消息

方式一:

        dashboard控制面板===>消息===>Topic===>选择死信队列主题 & 区间。

方式二:

        dashboard控制面板===>主题===>勾选死信===>刷新。

1.4、如何消费死信队列中的消息

/**
 * 消费死信队列中的消息
 * 
 * @throws Exception
 */
@Test
public void demo9RetryDeadConsumer() throws Exception {
	// 1、创建一个消费者
	DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-dead-consumer-group");
	// 2、连接NameServer
	consumer.setNamesrvAddr(RocketMQConstant.NAME_SERVER_ADDR);
	consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
	// 3、订阅消息,*表示订阅该主题所有的消息
	consumer.subscribe("%DLQ%retry-consumer-group", "*");
	// 4、设置监听器(采用异步回调方式,一直监听)
	consumer.registerMessageListener(new MessageListenerConcurrently() {
		@Override
		public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) {
			// 业务处理
			for (MessageExt message : messages) {
				log.info("将该条消息记录到MySQL | Redis | 通知人工处理...,消息内容:{}",StrUtil.utf8Str(message.getBody()));
			}

			/**
			 * 返回值:消费消息成功与否
			 *      CONSUME_SUCCESS:表明消费成功,消息会从MQ出队
			 *      RECONSUME_LATER:表明消费失败,消息会重新回到队里,过一会儿再重新投递出来给当前消费者或者其他消费者
			 * 什么时候消费者会重试?
			 *      (1)业务报错了
			 *      (2)返回null
			 *      (3)返回RECONSUME_LATER
			 */
			 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
		}
	});
	// 5、启动
	consumer.start();
	log.info("【demo9RetryDeadConsumer】启动成功,正在等待接收消息...");

	// 6、挂起当前JVM
	System.in.read();
}

### 关于死信队列的概念 死信队列(Dead Letter Queue, DLQ)是一种用于捕获无法正常处理的消息的机制。当某些条件满足时,原本存在于常规队列中的消息会被转移到一个特殊的队列——即死信队列中[^1]。 #### 死信队列的应用场景 死信队列通常被用来处理以下几种情况: - 消息过期:如果一条消息在队列中停留的时间超过了设定的最大时间,则该消息会成为死信。 - 消费失败:消费者尝试多次消费某条消息均未成功(达到最大重试次数),则这条消息也会进入死信队列。 - 队列满溢:目标队列已达到其容量上限而无法接受新消息时,这些消息可能被丢弃或者转入死信队列。 #### RabbitMQ 中的死信队列配置方法 要在 RabbitMQ 中启用并使用死信队列功能,可以通过设置特定参数来完成: ##### 设置步骤如下: 1. **定义主队列属性** 创建普通的队列时指定 `x-dead-letter-exchange` 和可选的 `x-dead-letter-routing-key` 参数。这告诉 RabbitMQ 当发生上述提到的情况之一时应如何处理那些变成“死信”的消息。 下面是一个 Python 示例代码展示如何声明带有死信特性的队列: ```python import pika connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 定义DLX exchange dlx_exchange_name = 'my.dlx.exchange' channel.exchange_declare(exchange=dlx_exchange_name, exchange_type='direct') # 主队列绑定到DLX Exchange上 queue_name = 'normal_queue' args = { 'x-message-ttl': 60000, 'x-dead-letter-exchange': dlx_exchange_name, 'x-dead-letter-routing-key': 'dead_letter_key' } channel.queue_declare(queue=queue_name, arguments=args) binding_key_normal = 'normal_key' channel.queue_bind( exchange='main_exchange', queue=queue_name, routing_key=binding_key_normal) print(f' [*] Waiting for messages on {queue_name}. To exit press CTRL+C') ``` 2. **创建对应的死信交换器和队列** 接下来要做的就是建立实际接收来自其他队列死亡消息的目标位置 —— 这里我们称之为 “死信交换器”。同样也需要关联相应的死信队列以便保存最终的数据副本。 对于 Kafka 来说,它本身并没有内置支持类似于 RabbitMQ 的死信队列概念,但是可以借助外部工具和服务实现类似的功能,比如通过 MirrorMaker 将未能及时消费的主题数据复制到另一个主题作为存档用途;或者是利用流处理框架如 Flink/Kafka Streams 对异常情况进行检测并将有问题记录写入专门设计好的错误日志表单之中等等方式达成目的[^2]。 #### 死信队列的工作原理与实现细节 无论是哪种 MQ 技术栈下所采用的具体做法有所差异,但从逻辑层面来看它们遵循着共同的原则流程图大致如下所示: ![image](https://www.example.com/image.png)[^4] 其中涉及到了几个核心组件及其交互关系描述如下: - 生产者向源队列发送原始业务请求; - 如果因为各种原因导致该笔事务得不到妥善处置就会触发相应规则判定从而落入预设路径直至抵达终点站也就是所谓的 Dead-Lettered State. 综上所述,在构建健壮可靠的信息传递基础设施过程中引入此类保护措施显得尤为重要不可或缺!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值