RabbitMQ——死信队列

RabbitMQ死信队列实现与应用:生产者与消费者操作

RabbitMQ——死信队列

死信队列(Dead Letter Queue,DLQ)是 RabbitMQ 中的一种重要特性,用于处理无法被消费的消息,防止消息丢失。

死信的来源

在消息队列中,当消息满足一定条件而无法被正常消费时,这些消息会被发送到死信队列。满足条件的情况包括但不限于:

  • 消息被拒绝(basic.rejectbasic.nack)且不重新入队(requeue 参数为 false)。
  • 消息过期(TTL,Time-To-Live)。
  • 队列长度超过限制,无法再添加数据到mq中。

生产者

package com.weipch.rabbitmq.dlq;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.GetResponse;
import com.weipch.util.RabbitMqUtils;

/**
 * @Author 方唐镜
 * @Create 2024-03-03 14:08
 * @Description
 */
public class Produce {


	private static final String NORMAL_EXCHANGE = "normal_exchange";


	public static void main(String[] args) throws Exception {
		Channel channel = RabbitMqUtils.getChannel();
        //模拟消息过期 10s
		//AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build();
		for (int i = 0; i < 10; i++) {
			String message = "hello world" + i;
			channel.basicPublish(NORMAL_EXCHANGE, "normal-routing-key", null, message.getBytes());
		}
	}
}

消费者

正常队列:

package com.weipch.rabbitmq.dlq;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;
import com.weipch.util.RabbitMqUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 方唐镜
 * @Create 2024-03-03 13:50
 * @Description
 */
public class Consumer01 {


	private static final String NORMAL_EXCHANGE = "normal_exchange";
	private static final String DEAD_EXCHANGE = "dead_exchange";

	private static final String NORMAL_QUEUE = "normal_queue";
	private static final String DEAD_QUEUE = "dead_queue";


	public static void main(String[] args) throws Exception {
		Channel channel = RabbitMqUtils.getChannel();
		//声明死信交换机和队列
		channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);
		channel.queueDeclare(DEAD_QUEUE, false, false, false, null);
		//绑定
		channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "dead-routing-key");


		//声明普通交换机和队列
		channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);
		//在正常队列中设置死信参数 指定死信交换机和死信路由键
		Map<String, Object> map = new HashMap<>();
		map.put("x-dead-letter-exchange", DEAD_EXCHANGE);
		map.put("x-dead-letter-routing-key", "dead-routing-key");
		//最大长度
		//map.put("x-max-length", 6);
		channel.queueDeclare(NORMAL_QUEUE, false, false, false, map);
		channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "normal-routing-key");
		DeliverCallback deliverCallback = (consumerTag, delivery) -> {
			String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
			if (message.contains("5")){
				System.out.println("Consumer01接收消息:" + message + ",此消息被拒绝");
				//拒绝消息并把消息丢入死信队列
				channel.basicReject(delivery.getEnvelope().getDeliveryTag(), false);
			}else {
				System.out.println("Consumer01接收消息:" + message);
				channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
			}
		};
		channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, (consumerTag, e) -> {});
	}
}

死信队列:

package com.weipch.rabbitmq.dlq;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.weipch.util.RabbitMqUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author 方唐镜
 * @Create 2024-03-03 13:50
 * @Description
 */
public class Consumer02 {
	
	private static final String DEAD_QUEUE = "dead_queue";

	public static void main(String[] args) throws Exception {
		Channel channel = RabbitMqUtils.getChannel();
		channel.basicConsume(DEAD_QUEUE, true,
			(consumerTag, delivery) -> System.out.println("Consumer02:" + new String(delivery.getBody(), StandardCharsets.UTF_8)),
			(consumerTag, e) -> {});
	}
}

生产者发送消息到正常队列,而消费者负责消费正常队列的消息。当消息被消费者拒绝并不再重新投递时,消息会被发送到死信队列。

### 配置与使用RabbitMQ中的死信队列 #### 1. Maven依赖导入 为了在项目中集成RabbitMQ并支持死信队列功能,需引入`spring-boot-starter-amqp`作为依赖项。 ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> ``` 此依赖提供了访问AMQP协议的支持以及Spring AMQP抽象层的功能[^1]。 #### 2. RabbitMQ连接配置 通过修改application.yml文件来设置RabbitMQ服务器的相关参数: ```yaml spring: rabbitmq: host: 83.136.16.134 port: 5672 username: guest password: guest listener: simple: acknowledge-mode: manual # 手动确认模式 default-requeue-rejected: false # 不重新入队被拒绝的消息 ``` 上述配置指定了RabbitMQ服务端地址、认证信息及监听器行为选项。其中手动应答机制(`acknowledge-mode`)对于处理失败重试逻辑至关重要;而关闭自动重排队列(`default-requeue-rejected=false`)则防止了因消费者异常而导致消息无限循环的问题。 #### 3. 死信队列的定义与绑定 创建一个专门用于接收过期或未成功消费的消息的死信交换机(DLX),并将目标业务队列与其关联起来。具体操作如下所示: - **声明DLX**: 定义一个直连型(dead-letter-exchange)或其他类型的交换机实例; - **设定策略属性**: 对于每一个可能产生死信的目标队列,在其声明时指定两个重要的头字段——`x-dead-letter-exchange`(指向DLX名称)`x-dead-letter-routing-key`(可选,指定转发给哪个路由键下的队列)。 以下是Java代码片段展示如何利用Spring Boot框架完成这些步骤: ```java @Configuration public class RabbitConfig { @Bean public Queue dlqQueue() { return new Queue("dlq.queue", true); } @Bean DirectExchange deadLetterExchange() { return new DirectExchange("my.deadletter.exchange"); } @Bean Binding bindingDead(Queue queue, DirectExchange direct){ Map<String,Object> args=new HashMap<>(); args.put("x-dead-letter-exchange","my.deadletter.exchange"); // 设置死信exchange args.put("x-message-ttl",1000); // 可选:设置TTL时间单位ms return BindingBuilder.bind(queue).to(direct).with("normal.routing.key").noargs(args); } } ``` 这段程序首先建立了名为`dlq.queue`的实际存储死信数据的目的地,并设置了相应的死信交换机`my.deadletter.exchange`。接着为正常工作的业务队列绑定了特定的路由规则的同时也赋予了一些额外参数用来指示哪些情况下应该触发向死信队列发送副本的行为。 #### 4. 处理来自死信队列的消息 最后一步就是编写对应的Listener组件去监控和响应那些进入到了死信队列里的内容。这通常涉及到解析原始消息体及其元数据(比如为什么它成为了死信),进而采取适当的动作如记录日志、通知相关人员或是尝试再次投递给其他地方继续流转下去。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里顾—程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值