RabbitMQ-死信队列DLX

一,死信队列

     利用DLX, 当消息在一个队列中变成死信(dead message)之后, 它能被重新publish到另一个Exchange, 这个Exchange就是DLX。
     DLX也是一个正常的Exchange, 和一般的Exchange没有区别, 它能在任何队列上被指定, 实际上就是设置某个队列的属性为死信队列。当这个队列中有死信时, RabbitMQ就会自动将这个消息重新发布到设置的Exchange上去, 进而被路由到另一个队列
可以监听这个队列中消息做相应的处理。

二,消息变成死信的几种情况

(1)消息被拒绝(basic.reject/basic.nack) 并且requeue重回队列设置成false
(2)消息TTL过期
(3)队列达到最大长度

三,死信队列的设置

     对于任何给定队列,DLX可以由使用队列参数的客户端定义,也可以 在使用策略的服务器中定义。在策略和参数都指定DLX的情况下,参数中指定的那个会覆盖策略中指定的那个。
建议使用策略进行配置,因为它允许不涉及应用程序重新部署的DLX重新配置。

1,使用策略配置

     要使用策略指定DLX,请将“dead-letter-exchange”键添加到策略定义中。例如:
在这里插入图片描述
     这将DLX“my-dlx”应用于所有队列。类似地,可以通过向策略添加密钥“dead-letter-routing-key”来指定显式路由密钥。

2,使用可选队列参数配置

     要为队列设置死信交换,需要在声明队列时指定可选的x-dead-letter-exchange参数,该值必须是同一虚拟主机中的交换名称。c++代码演示如下:
首先我们需要创建一个正常的队列:

amqp_queue_declare_ok_t *res = amqp_queue_declare(
		m_connectState, 
		channel_id, 
		amqp_cstring_bytes(queue.m_name.c_str()),
		queue.m_bPassive,	/*passive*/ 	//检验队列是否存在(同exchange中的passive属性)
		queue.m_durable,	/*durable*/ 	//队列是否持久化(即使mq服务重启也会存在)
		queue.m_bExclusive,  /*exclusive*/ 	//是否是专用队列(当前连接不在时,队列是否删除)
		queue.m_bAutoDelete,/*auto_delete*/  //是否自动删除(什么时候删除?。。。)
		amqp_table);
	amqp_rpc_reply_t rpc_reply = amqp_get_rpc_reply(m_connectState);
	if (0 != GetErrorText(rpc_reply, "amqp_queue_declare", ErrorReturn))
	{
		return -1;
	}

函数amqp_queue_declare的最后一个参数类型是amqp_table_t,结构声明如下:

typedef struct amqp_table_t_ {
  int num_entries;                     /**< length of entries array */
  struct amqp_table_entry_t_ *entries; /**< an array of table entries */
} amqp_table_t;

amqp_table_t是一个存储数组指针的结构体,其中的指针指向的是amqp_table_entry_t结构,声明如下:

typedef struct amqp_table_entry_t_ {
  amqp_bytes_t key; /**< the table entry key. Its a null-terminated UTF-8
                     * string, with a maximum size of 128 bytes */
  amqp_field_value_t value; /**< the table entry values */
} amqp_table_entry_t;

简单理解,它就是一个key,value形式的结构体,其中key是数据类型,value是具体的数据内容,我们需要填充如下:

//填充x_death
	int nTableNum = 3;
	amqp_table_entry_t *pTable = (amqp_table_entry_t*)malloc(sizeof(amqp_table_entry_t) * nTableNum);
	{
		pTable[0].key = amqp_cstring_bytes("x-dead-letter-exchange");
		pTable[0].value.value.bytes  =  amqp_cstring_bytes("dlx.default_message_push_exchange");
		pTable[0].value.kind = AMQP_FIELD_KIND_UTF8;

		pTable[1].key = amqp_cstring_bytes("x-dead-letter-routing-key");
		pTable[1].value.value.bytes = amqp_cstring_bytes("#");;
		pTable[1].value.kind = AMQP_FIELD_KIND_UTF8;

		pTable[2].key = amqp_cstring_bytes("x-max-length");	
		pTable[2].value.value.u16 = 200;
		pTable[2].value.kind = AMQP_FIELD_KIND_U16;
	}
	amqp_table.num_entries = 3;
	amqp_table.entries = pTable ;

     amqp_table_t填充完毕,创建新队列的时候传参进去,那么就相当于给该正常队列绑定了一个死信交换机,当出现上面讲述的三种情况时,消息将会进入死信队列。请注意,在声明队列时不必声明交换,但是当消息需要使用死信时它应该存在; 如果它丢失了,消息将被静默删除。
     因此,我们还需要再创建对应的死信交换机和死信队列,并通过x-dead-letter-routing-key将它们绑定在一起。简单理解:死信交换机和死信队列也可以当做正常的队列来进行声明,绑定和消费。
     如果x-dead-letter-routing-key没有设置,将使用消息自己原本的routing_key值。

3,通过web管理界面设置死信队列

     RabbitMQ服务部署后,可以通过15672端口直接访问mq的web管理界面,我们同样地也可以在这上面进行正常队列的死信队列创建和绑定操作,具体操作大家可以参照这一篇博客RabbitMQ管理界面配置死信队列

四,死信队列的优点

1,使用死信队列可以缓解生产者速度快,消费者速度慢的问题。
2,通过死信队列可以间接实现延迟消息的处理:正常的消息不设置延时,特殊消息设置延时,指定的消费者去消费对应的死信队列。
3,死信队列从另一个角度来说可以体现RabbitMQ的可靠性,异常情况下的消息并不会丢失,而是进入到死信队列中,再由消费者去消费。

参考文章:
1,https://www.rabbitmq.com/dlx.html
2,https://blog.youkuaiyun.com/love905661433/article/details/85449191
3,https://blog.youkuaiyun.com/zhanghan18333611647/article/details/79519085

### 配置与使用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组件去监控和响应那些进入到了死信队列里的内容。这通常涉及到解析原始消息体及其元数据(比如为什么它成为了死信),进而采取适当的动作如记录日志、通知相关人员或是尝试再次投递给其他地方继续流转下去。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Simple Simple

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

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

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

打赏作者

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

抵扣说明:

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

余额充值