一、什么是死信队列

当消息在一个队列中变成一个死信之后,它将被重新publish到另一个交换机上,这个交换机我们就叫做死信交换机,私信交换机将死信投递到一个队列上就是死信队列。具体原理如下图:

消息变成死信的三种情况:

  • 消息被拒绝(basic.reject / basic.nack),并且requeue = false
  • 消息TTL过期
  • 队列达到最大长度

二、手动签收应答模式

应答模式分为两种,手动签收和自动签收,自动应答就是消费者消费了一条消息就自动告诉队列删除消息。这样的弊端就是不管消费逻辑有没有成功,都会将消息删除,这样就会造成消息丢失。而使用手动签收后,就是在消费逻辑处理成功后,手动告诉队列消费成功,然后队列再去删除这条消息。

  1. 再消费者配置文件中开启手动签收模式
spring.rabbitmq.listener.simple.acknowledge-mode = manual
  1. 在消费逻辑处理成功后手动签收,修改消费者代码
@RabbitListener(queues = QUEUE_NAME)
public void receiveMessage(Message message,@Headers Map<String,Object> headers, Channel channel) throws Exception { Jedis jedis = new Jedis("localhost", 6379); String messageId = message.getMessageProperties().getMessageId();
String msg = new String(message.getBody(),"UTF-8");
System.out.println("接收导的消息为:"+msg+"==消息id为:"+messageId); String messageIdRedis = jedis.get("messageId"); if(messageId == messageIdRedis){
return;
}
JSONObject jsonObject = JSONObject.parseObject(msg);
String email = jsonObject.getString("email");
String content = jsonObject.getString("timestamp"); String httpUrl = "http://127.0.0.1:8080/email?email"+email+"&content="+content;
// 如果发生异常则返回null
String body = HttpUtils.httpGet(httpUrl, "utf-8");
//
if(body == null){
throw new Exception();
}
jedis.set("messageId",messageId);
Long deliveryTag = (Long)headers.get(AmqpHeaders.DELIVERY_TAG);
// 手动签收
channel.basicAck(deliveryTag,false);
}

三、产生死信的三种情况演示

  • 消息被拒绝

我们继续修改一下消费者代码,尝试让消费者消费的时候发生异常。然后在catch块中拒绝消息。

// 拒绝消息,给死信队列
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);

我们运行程序后发现,**当消息消费异常后在队列”zb-byte1“中的消息被消费了,同时发现在死信队列”dead-byte-zb“中有一条未被消费的消息。**消息到死信队列后,然后我们在创建一个消费者去消费消息就可以了。当然死信队列也需要去手动签收消息。

  • 消息TTL过期

这种模式我们也叫做延迟消费,有一种特别经典的案例就是用户在一个商品抢购系统中,用户抢到商品后需要在30分钟时间内支付,不然订单无效。这时候我们就可以通过消息TTL过期来实现,设置队列消息过期时间为30分钟,30分钟后publish到死信队列,我们在死信队列中消费订单状态是否支付成功来判断该订单是否有效。

非常简单,我们只需要在配置死信交换机的时候设置有效时间就可以了

  @Bean
public Queue queue(){ Map<String,Object> map = new HashMap<>();
map.put("x-dead-letter-exchange",BEI_EXCHANGE_NAME);
map.put("x-dead-letter-routing-key",BEI_ROUTING_KEY);
map.put("x-message-ttl",7200); // 队列过期时间
Queue queue = new Queue(QUEUE_NAME,true,false,false,map);
return queue;
}
  • 队列达到最大长度

设置队列长度即可:

 @Bean
public Queue queue(){ Map<String,Object> map = new HashMap<>();
map.put("x-dead-letter-exchange",BEI_EXCHANGE_NAME);
map.put("x-dead-letter-routing-key",BEI_ROUTING_KEY);
map.put("x-max-length",3);
// map.put("x-message-ttl",7200); // 队列过期时间
Queue queue = new Queue(QUEUE_NAME,true,false,false,map);
return queue;
}

设置好之后,我们先不要启动消费者,然后调用生成者往队列中发送消息,当消息长度大于3时,我们发现消息进入了死信队列。

注意:前文中也提到过,队列不能被修改,也就是说已经创建好的队列设置了过期时常为7200s,然后我们注释掉,增加队列长度是3的代码,这样运行会报错,必须在rabbitmq中将该队列删除,然后重新生成队列才可以。

如果文章对您有帮助,请记得点赞关注哟~
欢迎大家关注我的公众号:字节传说,每日推送技术文章供大家学习参考。

rabbitmq系列(四)死信队列的更多相关文章

  1. 关于 RabbitMQ 的 Dead-Letters-Queue “死信队列”

      来自一个队列的消息可以被当做‘死信’,即被重新发布到另外一个“exchange”去,这样的情况有: 消息被拒绝 (basic.reject or basic.nack) 且带 requeue=fa ...

  2. Rabbitmq消费失败死信队列

    Rabbitmq 重消费处理 一 处理流程图: 业务交换机:正常接收发送者,发送过来的消息,交换机类型topic AE交换机: 当业务交换机无法根据指定的routingkey去路由到队列的时候,会全部 ...

  3. RabbitMQ TTL、死信队列

    TTL概念 TTL是Time To Live的缩写,也就是生存时间. RabbitMQ支持消息的过期时间,在消息发送时可以进行指定. RabbitMQ支持队列的过期时间,从消息入队列开始计算,只要超过 ...

  4. RabbitMQ (五):死信队列

    什么是TTL RabbitMQ的TTL全称为Time-To-Live,表示的是消息的有效期.消息如果在队列中一直没有被消费并且存在时间超过了TTL,消息就会变成了"死信" (Dea ...

  5. rabbitmq系列四 之路由

    1.路由 在上一个的教程中,我们构建了一个简单的日志记录系统.我们能够向许多接收者广播日志消息. 在本次教程中,我们向该系统添加一些特性,比如,我只需要严重错误(erroe级别)的部分日志打印到磁盘文 ...

  6. RabbitMQ系列(四)--消息如何保证可靠性传输以及幂等性

    一.消息如何保证可靠性传输 1.1.可能出现消息丢失的情况 1.Producer在把Message发送Broker的过程中,因为网络问题等发生丢失,或者Message到了Broker,但是出了问题,没 ...

  7. RabbitMQ使用 prefetch_count优化队列的消费,使用死信队列和延迟队列实现消息的定时重试,golang版本

    RabbitMQ 的优化 channel prefetch Count 死信队列 什么是死信队列 使用场景 代码实现 延迟队列 什么是延迟队列 使用场景 实现延迟队列的方式 Queue TTL Mes ...

  8. RabbitMQ死信队列

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

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

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

随机推荐

  1. python基础 生成器 迭代器

    列表生成式: a=[1,2,3] print a b=[i*2 for i in range(10)] #i循环10次,每一个i的值乘2就是列表中的值.列表生成式 print b >>[1 ...

  2. SpringBoot 处理 POST Json 传参枚举

    在 Spring 框架中对枚举类型的序列化/反序列化是有限制的. 假设如下面这样在某些情况下就不能正常工作: 123456789 public enum PayChannelEnum implemen ...

  3. spring cloud实战 1-高可用注册中心

    创建父maven项目 提交代码至GitHub 创建eureka-server-1 项目搭建两种方式: 父pom中继承spring-boot-starter-parent,子pom中直接结成父pom.该 ...

  4. mongodb写入安全级别

    MongoDB的写安全机制 写入安全(Write Concern)是一种由客户端设置的,用于控制写入安全级别的机制,通过使用写入安全机制可以提高数据的可靠性. MongoDB提供四种写入级别,分别是: ...

  5. 【教程向】配置属于自己的vim

    新建Vim配置文件 Linux mkdir -/.vimrc 配置 常用设置 配置 功能 set number 设置行号 set systax on 高亮 colorscheme{主题} 设置颜色主题 ...

  6. 如何通过学校系统漏洞注册到 @edu.cn 邮箱账号?

    此文章仅针对我自己学校的系统进行分析,并不代表所有学校的系统都是如此. 我们学校比较"抠",可能是为了节省学校的带宽资源然后禁止学生注册教育邮箱账号.不过像一部电影所说的那样&qu ...

  7. RTL8812AU双频无线网卡在ubuntu19和20上的驱动安装

    旧爱已去 疫情在家,突然邻居敲门说,我这网上不了,帮下忙呗兄弟:兄弟都叫了,哥就冒回险,口罩扎起,一顿xxxx,原来是路由器没插到wlan口,看他拉网线可怜,就把我台式机上无线网卡送给他了,这就是又送 ...

  8. python爬虫-MongoDB安装配置

    MongoDB安装配置: 在安装配置MongoDB的过程中遇到了很多问题,现在重新梳理一遍安装流程.遇到的问题及其解决方法 系统版本:Windows 10 MongoDB版本:4.2.1 1.下载地址 ...

  9. 201771010105—达拉草 实验一 软件工程准备—<软件工程构建之法—初步了解和认识>

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  10. PostgreSQL没有认证密码就登陆了缘由

    上午同事爆出这样的问题,使用正确的用户名和错误的密码连接了postgresql数据库,竟然连上了.这不是故意这样神操作,不小心密码写错了,咋一看这样怎么能行,随便输入一个密码都能登陆上.自己测试也是同 ...