何为死信队列?

死信队列实际上就是,当我们的业务队列处理失败(比如抛异常并且达到了retry的上限),就会将消息重新投递到另一个Exchange(Dead Letter Exchanges),该Exchange再根据routingKey重定向到另一个队列,在这个队列重新处理该消息。

来自一个队列的消息可以被当做‘死信’,即被重新发布到另外一个“exchange”去,这样的情况有:
  • 消息被拒绝 (basic.reject or basic.nack) 且带 requeue=false不重新入队参数或达到的retry重新入队的上限次数
  • 消息的TTL(Time To Live)-存活时间已经过期
  • 队列长度限制被超越(队列满,queue的"x-max-length"参数)
 
Dead letter exchanges (DLXs) are normal exchanges.
 
For any given queue, a DLX can be defined by clients using the queue's arguments, or in the server using policies.
 
经过上面的认知,可知应用场景:重要的业务队列如果失败,就需要重新将消息用另一种业务逻辑处理;如果是正常的业务逻辑故意让消息中不合法的值失败,就不需要死信;具体场景具体分析。

SpringBoot配置文件

设置重试次数、间隔和投递到死信队列

spring.application.name=spring-boot-rabbitmq
spring.rabbitmq.host=localhost
spring.rabbitmq.port=
spring.rabbitmq.username=nut
spring.rabbitmq.password=nut # 允许消息消费失败的重试
spring.rabbitmq.listener.simple.retry.enabled=true
# 消息最多消费次数3次
spring.rabbitmq.listener.simple.retry.max-attempts=
# 消息多次消费的间隔1秒
spring.rabbitmq.listener.simple.retry.initial-interval=
# 设置为false,会丢弃消息或者重新发布到死信队列
spring.rabbitmq.listener.simple.default-requeue-rejected=false server.port=

初始化和绑定重定向队列配置类

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.HashMap;
import java.util.Map; /**
* 死信队列的配置
*/
@Configuration
public class RabbitDeadLetterConfig { public static final String DEAD_LETTER_EXCHANGE = "TDL_EXCHANGE";
public static final String DEAD_LETTER_TEST_ROUTING_KEY = "TDL_KEY";
public static final String DEAD_LETTER_REDIRECT_ROUTING_KEY = "TKEY_R";
public static final String DEAD_LETTER_QUEUE = "TDL_QUEUE";
public static final String REDIRECT_QUEUE = "TREDIRECT_QUEUE"; /**
* 死信队列跟交换机类型没有关系 不一定为directExchange 不影响该类型交换机的特性.
*/
@Bean("deadLetterExchange")
public Exchange deadLetterExchange() {
return ExchangeBuilder.directExchange(DEAD_LETTER_EXCHANGE).durable(true).build();
} @Bean("deadLetterQueue")
public Queue deadLetterQueue() {
Map<String, Object> args = new HashMap<>(2);
// x-dead-letter-exchange 声明 死信队列Exchange
args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
// x-dead-letter-routing-key 声明 死信队列抛出异常重定向队列的routingKey(TKEY_R)
args.put("x-dead-letter-routing-key", DEAD_LETTER_REDIRECT_ROUTING_KEY);
return QueueBuilder.durable(DEAD_LETTER_QUEUE).withArguments(args).build();
} @Bean("redirectQueue")
public Queue redirectQueue() {
return QueueBuilder.durable(REDIRECT_QUEUE).build();
} /**
* 死信队列绑定到死信交换器上.
*
* @return the binding
*/
@Bean
public Binding deadLetterBinding() {
return new Binding(DEAD_LETTER_QUEUE, Binding.DestinationType.QUEUE, DEAD_LETTER_EXCHANGE, DEAD_LETTER_TEST_ROUTING_KEY, null); } /**
* 将重定向队列通过routingKey(TKEY_R)绑定到死信队列的Exchange上
*
* @return the binding
*/
@Bean
public Binding redirectBinding() {
return new Binding(REDIRECT_QUEUE, Binding.DestinationType.QUEUE, DEAD_LETTER_EXCHANGE, DEAD_LETTER_REDIRECT_ROUTING_KEY, null);
}
}

生产者向业务队列发送消息

这里为了方便测试没有往业务队列发送消息,直接往死信Exchange里投递消息。

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import xy.study.rabbitmq.conf.RabbitDeadLetterConfig; @Slf4j
@Component
public class DeadLetterSender { @Autowired
private RabbitTemplate rabbitTemplate; public void send(int number) {
log.warn("DeadLetterSender : {}", number);
// 这里的Exchange可以是业务的Exchange,为了方便测试这里直接往死信Exchange里投递消息
rabbitTemplate.convertAndSend(
RabbitDeadLetterConfig.DEAD_LETTER_EXCHANGE,
RabbitDeadLetterConfig.DEAD_LETTER_TEST_ROUTING_KEY,
number);
}
}

死信队列消费者

这里会抛异常

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import xy.study.rabbitmq.conf.RabbitDeadLetterConfig; @Slf4j
@Component
@RabbitListener(queues = RabbitDeadLetterConfig.DEAD_LETTER_QUEUE)
public class DeadLetterConsumer { /*@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = RabbitDeadLetterConfig.DEAD_LETTER_QUEUE, durable = "true"),
exchange = @Exchange(value = RabbitDeadLetterConfig.DEAD_LETTER_EXCHANGE, type = ExchangeTypes.DIRECT),
key = RabbitDeadLetterConfig.DEAD_LETTER_TEST_ROUTING_KEY)
)*/
@RabbitHandler
public void testDeadLetterQueueAndThrowsException(@Payload Integer number){
log.warn("DeadLetterConsumer :{}/0 ", number);
int i = number / 0;
}
}

重定向队列

队列"死信"后,会将消息投递到Dead Letter Exchanges,然后该Exchange会将消息投递到重定向队列。

此时,在重定向队列中,做对应的业务操作。

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import xy.study.rabbitmq.conf.RabbitDeadLetterConfig; @RabbitListener(queues = RabbitDeadLetterConfig.REDIRECT_QUEUE)
@Component
@Slf4j
public class RedirectQueueConsumer { /**
* 重定向队列和死信队列形参一致Integer number
* @param number
*/
@RabbitHandler
public void fromDeadLetter(Integer number){
log.warn("RedirectQueueConsumer : {}", number);
// 对应的操作
int i = number / 1;
}
}

测试

先启动项目

然后利用测试类发送一条信息

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import xxx.DeadLetterSender; @RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqApplicationTests { @Autowired
private DeadLetterSender deadLetterSender; @Test
public void testSendDeadLetterQueue(){
deadLetterSender.send(15);
} }

再看RabbitmqApplication控制台日志

重试3次后,消息不再入队,投递到DL Exchange,路由到重定向队列。

SpringBoot RabbitMQ 延迟队列代码实现

参考:

http://www.cnblogs.com/wei-feng/p/6599419.html

https://my.oschina.net/10000000000/blog/1626278

springboot rabbitmq 死信队列应用场景和完整demo的更多相关文章

  1. 【RabbitMQ】一文带你搞定RabbitMQ死信队列

    本文口味:爆炒鱿鱼   预计阅读:15分钟 一.说明 RabbitMQ是流行的开源消息队列系统,使用erlang语言开发,由于其社区活跃度高,维护更新较快,性能稳定,深得很多企业的欢心(当然,也包括我 ...

  2. RabbitMQ死信队列另类用法之复合死信

    前言 在业务开发过程中,我们常常需要做一些定时任务,这些任务一般用来做监控或者清理任务,比如在订单的业务场景中,用户在创建订单后一段时间内,没有完成支付,系统将自动取消该订单,并将库存返回到商品中,又 ...

  3. rabbitmq死信队列消息监听

    #邮件通知并发送队列消息#!/bin/bash maillog="/var/log/mq.maillog" message_file="/tmp/mq_message&q ...

  4. SpringBoot RabbitMQ 延迟队列代码实现

    场景 用户下单后,如果30min未支付,则删除该订单,这时候就要可以用延迟队列 准备 利用rabbitmq_delayed_message_exchange插件: 首先下载该插件:https://ww ...

  5. 【MQ中间件】RabbitMQ -- RabbitMQ死信队列及内存监控(4)

    1.RabbitMQ TTL及死信队列 1.1.TTL概述 过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取:过了之后消息将自动被删除.RabbitMQ可以对消息和队列设 ...

  6. rabbitmq死信队列和延时队列的使用

    死信队列&死信交换器:DLX 全称(Dead-Letter-Exchange),称之为死信交换器,当消息变成一个死信之后,如果这个消息所在的队列存在x-dead-letter-exchange ...

  7. .Net Core&RabbitMQ死信队列

    过期时间 RabbitMQ可以为消息和队列设置过期时间Time To Live(TTL).其目的即过期. 消息过期时间 消息存储在队列中时,如果想为其设置一个有限的生命周期,而不是一直存储着,可以为其 ...

  8. RabbitMQ 死信队列 延时

    package com.hs.services.config; import java.util.HashMap; import java.util.Map; import org.springfra ...

  9. RabbitMQ死信队列

    关于RabbitMQ死信队列 死信队列 听上去像 消息“死”了     其实也有点这个意思,死信队列  是 当消息在一个队列 因为下列原因: 消息被拒绝(basic.reject/ basic.nac ...

随机推荐

  1. [LeetCode] 170. Two Sum III - Data structure design 两数之和之三 - 数据结构设计

    Design and implement a TwoSum class. It should support the following operations:add and find. add - ...

  2. ASP.NET Core Restful Web API 相关资源索引

    GraphQL 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(上) 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(下) [视频] 使用ASP.NET C ...

  3. Clean code 关于注释、函数、命名的感想

    最近在看代码整洁之道(Clean code)这本书,其实看的有点痛苦,因为越看就会越想自己写的代码是什么鬼?一些不知所云的命名,不整洁的代码格式,本想诠释代码的意思却添加了一段段废话,还有那些被强制加 ...

  4. 【剑指offer】面试题 6. 从尾到头打印链表

    面试题 6. 从尾到头打印链表 NowCoder 题目描述 输入一个链表的头结点,从尾到头反过来打印出每个结点的值. Java 实现 ListNode Class class ListNode { i ...

  5. 本地yum源 、阿里yum源、163yum源的配置安装

    一.本地yum源 (我使用的7.3版本) 1..添加一个新的yum源配置文件dvd.repo(文件名字自定义) vi etc/yum.repos.d     添加新的内容: name=rhel_dvd ...

  6. CSS中position 和float的使用说明(清晰)

    当构建页面排版时,有不同的方法可以使用.使用哪一种方法取决于具体页面的排版要求,在不同的情况下,某些方法可能好过于其他的方法. 比如,可以使用若干个浮动元素来构建一个整洁简洁的页面排版.或者,如果需要 ...

  7. PAT(B) 1090 危险品装箱(Java)

    题目链接:1090 危险品装箱 (25 point(s)) 题目描述 集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里.比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸. 本题 ...

  8. exit status 1

  9. AGC028E High Elements 贪心、DP、线段树

    传送门 看到要求"字典序最小"的方案,一个很直观的想法是按位贪心,那么我们需要check的就是当某一个数放在了第一个序列之后是否还存在方案. 假设当前两个序列的最大值和前缀最值数量 ...

  10. UOJ343 清华集训2017 避难所 构造、打表

    传送门 玄学题 考虑构造三个数\(p_1p_2,p_1p_2,p_1p_2\)满足贪心分解会分解为\(p_1^3,p_2,p_2,p_2\),那么需要满足条件 1.\(p_1 , p_2 \in Pr ...