springboot 监控队列_springboot rabbitmq 死信队列应用场景和完整demo

何为死信队列?

死信队列实际上就是,当我们的业务队列处理失败(比如抛异常并且达到了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 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,路由到重定向队列。

参考:

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

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

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

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

rabbitmq死信队列消息监听

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

SpringBoot RabbitMQ 延迟队列代码实现

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

RabbitMQ 死信队列 延时

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

RabbitMQ死信队列

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

springboot rabbitMQ 死信对列 实现消息的可靠消费

1 引入 maven 依赖 org.springframework.boot

springboot~rabbitmq的队列初始化和绑定

配置文件,在rabbit中自动建立exchange,queue和绑定它们的关系 代码里初始化exchange 代码里初始化queue 代码里绑定exchange,queue和routekey 配置文件 ...

RabbitMQ实战-死信队列

RabbitMQ死信队列 场景说明 代码实现 简单的Util 生产者 消费者 场景说明 场景: 当队列的消息未正常被消费时,如何解决? 消息被拒绝并且不再重新投递 消息超过有效期 队列超载 方案: 未 ...

随机推荐

EUI List列表实现人物列表

一  Scroll+List ,拖动组件到exml. List不能写定高度,不然无法自动扩展.  二 新建List条目皮肤, ListItemSkin皮肤 名字Label的文本{data.name} ...

[Unity菜鸟] Unity Web Player 相关问题 (待完善)

1. 发布网页版Unity自适应网页大小 发布网页版,Unity3D自适应网页大小.这个问题困扰了我很长时间,今天终于把他解决了,给大家分享一下. 这里用Uinty4.0发布网页版,我去掉了里面的标题 ...

post 提交数据

1 默认:application/x-www-form-urlencoded 在网页表单中可设置 enctype的值,如果不设,默认是 application/x-www-form-urlencode ...

NavBarControl 左侧菜单

(1)示例图片 具体实现: 一. using DevExpress.XtraNavBar; 二. 从窗体上拖一个 NavBarControl 控件 命名为:nbcLeft 三.窗体OnLoad 事件 ...

MVC 区域模块

mvc4.0新增的area区域机制,可以协助你在架构较为大型的项目,让独立性较高的部分功能独立成一个MVC子网站,以降低网站与网站之间的耦合性,也可以通过area的切割,让多人同时开发同一个项目时候, ...

Notes over compiling..

When compiling VIM on windows, using nmake may be a better choice.. Because so far my attempts to co ...

Django中的视图(view)

视图 1.什么是视图 视图就是Django项目下的view.py文件,它的内部是一系列的函数或者是类,用来专门处理客户端访问请求后处理请求并且返回相应的数据,相当于一个中央情报处理系统 2.具体视图实 ...

linux中,history命令,显示时间戳?操作人?IP地址?

需求描述: 在linux环境中,有的时候为了审计的需要,要记录谁什么时间从什么IP登录,执行了什么命令,bash的history命令就能够记录这些信息,但是在默认的情况下,是不记录时间的,所以呢,在这 ...

cocos2d-x:初探TestLua

打开\cocos2d-x-2.2.3\cocos2d-win32.vc2012.sln sln里面有个TestLuaproject 初探完成...(不要逗) 启动一下project,cocos2d-x ...

你可能感兴趣的:(springboot,监控队列)