6.【RabbitMQ实战】- 死信队列
概念
死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到queue 里了,consumer 从 queue 取出消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。
应用场景
为了保证订单业务的消息数据不丢失,需要使用到 RabbitMQ 的死信队列机制,当消息 消费发生异常时,将消息投入死信队列中.还有比如说: 用户在商城下单成功并点击去支付后在指定时 间未支付时自动失效
死信的来源
- 消息TTL过期
- 队列达到最大长度(队列满了,无法添加数据到mq中)
- 消息被拒绝(basic.reject或basic.nack)并且requeue = false
消息TTL过期
生产者代码
消费者代码
Consumer1代码
using rabbitmq.common;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
namespace Exchange.Consumer1
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("C1 开始接消息");
using var channel = RabbitmqUntils.GetChannel();
/*
申明一个 test_exchange 交换机
配置转发到死信队列参数
绑定交换机与对列
*/
channel.ExchangeDeclare(RabbitmqUntils.test_exchange, "direct",false,false,null);
var arguments = new Dictionary<string, object> { };
arguments.Add("x-dead-letter-exchange", "dead_exchange");//正常队列设置死信交换机 参数 key 是固定值
arguments.Add("x-dead-letter-routing-key", "dead");//正常队列设置死信 routing-key 参数 key 是固定值
channel.QueueDeclare(RabbitmqUntils.test_queue, false,false,false, arguments);
channel.QueueBind(RabbitmqUntils.test_queue, RabbitmqUntils.test_exchange, RabbitmqUntils.test_routingkey, null);
/*
申明一个死信交换机
绑定交换机与对列
*/
channel.ExchangeDeclare(RabbitmqUntils.dead_exchange, "direct", false, false, null);
channel.QueueDeclare("dead_queue", false, false, false, null);
channel.QueueBind(RabbitmqUntils.dead_queue, RabbitmqUntils.dead_exchange, RabbitmqUntils.dead_routingkey, null);
//事件对象
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queue: RabbitmqUntils.test_queue, true, consumer);
consumer.Received += (sender, e) =>
{
var body = e.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("C1 接收消息: {0}", message);
};
Console.ReadKey();
}
}
}
Consumer2代码
using rabbitmq.common;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
namespace Exchange.Consumer2
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("C2 开始接消息");
using var channel = RabbitmqUntils.GetChannel();
/*
申明一个死信交换机
绑定交换机与对列
*/
channel.ExchangeDeclare(RabbitmqUntils.dead_exchange, "direct", false, false, null);
channel.QueueDeclare("dead_queue", false, false, false, null);
channel.QueueBind(RabbitmqUntils.dead_queue, RabbitmqUntils.dead_exchange, RabbitmqUntils.dead_routingkey, null);
//事件对象
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queue: "dead_queue", true, consumer);
consumer.Received += (sender, e) =>
{
var body = e.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("C2 接收消息: {0}", message);
};
Console.ReadKey();
}
}
}
测试效果
- 先启动C1 创建交换机,队列和交换机与对列之间的绑定关系
- 此时关闭C1,模拟C1无法正常消费
- 启动生产者发送10条数据, 可在
test_queue
先有10条数据,10s后test_queue
10条数据消息,已将10条数据转发到dead_queue
中
- 最后启动C2 消费死信队列中的数据
队列达到最大长度
生产者去掉设置ttl
C1 添加代码
启动C1之前先删除队列否则会出现一下错误:
测试效果
消息被拒绝
C1代码调整
去掉设置长度限制代码并删除队列重新启动C1
调整为手动应答 autoAck:false
测试效果
分类:
RabbitMQ实战
标签:
RabbitMQ
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2021-04-12 工具分享:(一)【dev-sidecar】解决Github无法访问,国内dns污染问题