RabbitMQ死信队列及延迟队列

新手笔记,存在错误还请指正

尚硅谷RabbitMQ
rabbitmq官方文档

RabbitMQ死信队列及延迟队列

  • RabbitMQ死信队列及延迟队列
  • 死信队列:
  • 死信的例子
    • 消息 TTL 过期
    • 队列达到最大长度
    • 消息被拒
  • 延迟队列
    • 延迟队列使用场景
    • 延迟队列测试
      • 代码架构
      • 延迟队列优化
      • 基于插件实现的延迟队列

死信队列:

死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到queue 里了,consumer 从 queue 取出消息。进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如果没有后续的处理,就变成了死信,有死信自然就有了死信队列。
应用场景:为了保证订单业务的消息数据不丢失,需要使用到 RabbitMQ 的死信队列机制,当消息消费发生异常时,将消息投入死信队列中.还有比如说: 用户在商城下单成功并点击去支付后在指定时
间未支付时自动失效。
死信的来源
消息 TTL 过期
队列达到最大长度(队列满了,无法再添加数据到 mq 中)
消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false.

死信的例子

消息 TTL 过期


生产者代码:


/*** 死信队列,生产者*/
public class Producer {private static final String NORMAL_EXCHANGE = "normal_exchange";public static void main(String[] args) throws Exception{Channel channel= (Channel) RabbitMqUtils.getChannel();channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);//设置死信消息的 TTL 时间   10sAMQP.BasicProperties properties =new AMQP.BasicProperties().builder().expiration("10000").build();//该信息是用作演示队列个数限制for (int i = 1; i <11 ; i++) {String message="info"+i;channel.basicPublish(NORMAL_EXCHANGE,"zhangsan",properties,message.getBytes());System.out.println("生产者发送消息:"+message);}}
}

消费者01代码

/*** 死信队列* 消费者1*/
public class Consumer01 {//普通交换机名称private static final String NORMAL_EXCHANGE = "normal_exchange";//死信交换机名称private static final String DEAD_EXCHANGE = "dead_exchange";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();//声明死信和普通交换机 类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);//声明死信队列String deadQueue = "dead-queue";channel.queueDeclare(deadQueue, false, false, false, null);//死信队列绑定死信交换机与 routingkeychannel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");//正常队列绑定死信队列信息Map<String, Object> params = new HashMap<>();
//        //过期时间
//        params.put("x-message-ttl",10000);//10s//正常队列设置死信交换机 参数 key 是固定值params.put("x-dead-letter-exchange", DEAD_EXCHANGE);//正常队列设置死信 routing-key 参数 key 是固定值params.put("x-dead-letter-routing-key", "lisi");//声明正常队列String normalQueue = "normal-queue";channel.queueDeclare(normalQueue, false, false, false, params);//普通队列绑定普通交换机与 routingkeychannel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息........... ");DeliverCallback deliverCallback = (consumerTag, delivery) ->{String message = new String(delivery.getBody(), "UTF-8");System.out.println("Consumer01 接收到消息"+message);};channel.basicConsume(normalQueue,true,deliverCallback,consumerTag -> {});}
}


消费者 2 代码(以上步骤完成后 启动 2 消费者 它消费死信队列里面的消息)


/*** 死信队列* 消费者2*/
public class Consumer02 {//普通交换机名称private static final String NORMAL_EXCHANGE = "normal_exchange";//死信交换机名称private static final String DEAD_EXCHANGE = "dead_exchange";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);String deadQueue = "dead-queue";channel.queueDeclare(deadQueue, false, false, false, null);channel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");System.out.println("等待接收消息........... ");DeliverCallback deliverCallback = (consumerTag, delivery) ->{String message = new String(delivery.getBody(), "UTF-8");System.out.println("Consumer01 接收到消息"+message);};channel.basicConsume(deadQueue,true,deliverCallback,consumerTag -> {});}
}

队列达到最大长度

1、 消息生产者代码去掉 TTL 属性
2、1 消费者修改以下代码(启动之后关闭该消费者 模拟其接收不到消息)

//正常队列设置死信 routing-key 参数 key 是固定值params.put("x-dead-letter-routing-key", "lisi");//声明正常队列长度限制params.put("x-max-length",6);

注意此时需要把原先队列删除 因为参数改变了.
3. 2 消费者代码不变(启动 2 消费者)

消息被拒

1.消息生产者代码同上生产者一致
2.1 消费者代码(启动之后关闭该消费者 模拟其接收不到消息)

/*** 死信队列* 消费者1*/
public class Consumer01 {//普通交换机名称private static final String NORMAL_EXCHANGE = "normal_exchange";//死信交换机名称private static final String DEAD_EXCHANGE = "dead_exchange";public static void main(String[] args) throws Exception {Channel channel = RabbitMqUtils.getChannel();//声明死信和普通交换机 类型为 directchannel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT);channel.exchangeDeclare(DEAD_EXCHANGE, BuiltinExchangeType.DIRECT);//声明死信队列String deadQueue = "dead-queue";channel.queueDeclare(deadQueue, false, false, false, null);//死信队列绑定死信交换机与 routingkeychannel.queueBind(deadQueue, DEAD_EXCHANGE, "lisi");//正常队列绑定死信队列信息Map<String, Object> params = new HashMap<>();
//        //过期时间
//        params.put("x-message-ttl",10000);//10s//正常队列设置死信交换机 参数 key 是固定值params.put("x-dead-letter-exchange", DEAD_EXCHANGE);//正常队列设置死信 routing-key 参数 key 是固定值params.put("x-dead-letter-routing-key", "lisi");//声明正常队列长度限制// params.put("x-max-length",6);String normalQueue = "normal-queue";channel.queueDeclare(normalQueue, false, false, false, params);//普通队列绑定普通交换机与 routingkeychannel.queueBind(normalQueue, NORMAL_EXCHANGE, "zhangsan");System.out.println("等待接收消息........... ");DeliverCallback deliverCallback = (consumerTag, delivery) ->{String msg = new String(delivery.getBody(), "UTF-8");if(msg.equals("info5")){System.out.println("Consumer01 接收到消息"+msg+"此消息是被c1拒绝的");//拒绝该消息(不放回普通队列)/requeue 设置为 false 代表拒绝重新入队channel.basicReject(delivery.getEnvelope().getDeliveryTag(),false);}else{System.out.println("Consumer01 接收到消息"+msg);}};//开启手动应答channel.basicConsume(normalQueue,false,deliverCallback,consumerTag -> {});}
}

延迟队列

延时队列,队列内部是有序的,最重要的特性就体现在它的延时属性上,延时队列中的元素是希望
在指定时间到了以后或之前取出和处理,简单来说,延时队列就是用来存放需要在指定时间被处理的
元素的队列。

延迟队列使用场景

1.订单在十分钟之内未支付则自动取消
2.新创建的店铺,如果在十天内都没有上传过商品,则自动发送消息提醒。
3.用户注册成功后,如果三天内没有登陆则进行短信提醒。
4.用户发起退款,如果三天内没有得到处理则通知相关运营人员。
5.预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议
即:需要在某个事件发生之后或者之前的指定时间点完成某一项任务。
如:
发生订单生成事件,在十分钟之后检查该订单支付状态,然后将未支付的订单进行关闭;看起来似乎
使用定时任务,一直轮询数据,每秒查一次,取出需要被处理的数据,然后处理不就完事了吗?如果
数据量比较少,确实可以这样做,比如:对于“如果账单一周内未支付则进行自动结算”这样的需求,
如果对于时间不是严格限制,而是宽松意义上的一周,那么每天晚上跑个定时任务检查一下所有未支
付的账单,确实也是一个可行的方案。但对于数据量比较大,并且时效性较强的场景,如:“订单十
分钟内未支付则关闭“,短期内未支付的订单数据可能会有很多,活动期间甚至会达到百万甚至千万
级别,对这么庞大的数据量仍旧使用轮询的方式显然是不可取的,很可能在一秒内无法完成所有订单
的检查,同时会给数据库带来很大压力,无法满足业务要求而且性能低下。

延迟队列测试

引入的依赖:

<!--amqp--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><!--RabbitMQ 测试依赖--><dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency>

properties配置文件:

spring.rabbitmq.host=xxx.xxx.xxx
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123
spring.mvc.pathmatch.matching-strategy=ant_path_matcher  #springboot版本过高时报空指针错误,加上这句话

添加Swagger 配置类

package com.atguigu.rabbitmq.Config;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class SwaggerConfig {public Docket webApiConfig(){return new Docket(DocumentationType.SWAGGER_2).groupName("webApi").apiInfo(webApiInfo()).select().build();}private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("rabbitmq 接口文档").description("本文档描述了 rabbitmq 微服务接口定义").version("1.0").contact(new Contact("enjoy6288", "http://atguigu.com","1551388580@qq.com")).build();}}

代码架构

创建两个队列 QA 和 QB,两者队列 TTL 分别设置为 10S 和 40S,然后在创建一个交换机 X 和死信交换机 Y,它们的类型都是direct,创建一个死信队列 QD,它们的绑定关系如下:

配置文件类代码

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** TTL队列,配置文件类代码*/
@Configuration
public class TtlQueueConfig {//普通交换机的名称public static final String X_EXCHANGE = "X";//普通队列的名称public static final String QUEUE_A = "QA";public static final String QUEUE_B="QB";//死信交换机的名称public static final String Y_DEAD_LETTER_EXCHANGE = "Y";//死信队列的名称public static final String DEAD_LETTER_QUEUE="QD";// 声明xExchange@Bean("xExchange")public DirectExchange xExchange() {return new DirectExchange(X_EXCHANGE);}// 声明yExchange@Bean("yExchange")public DirectExchange yExchange(){return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);}//声明队列Attl为10s并绑定到对应的死信交换机@Bean("queueA")public Queue queueA(){Map<String,Object> args=new HashMap<>(3);//声明当前队列绑定的死信交换机args.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);//声明当前队列的死信路由keyargs.put("x-dead-letter-routing-key","YD");//声明队列的TTLargs.put("x-message-ttl",10000);return QueueBuilder.durable(QUEUE_A).withArguments(args).build();}// 声明队列A绑定X交换机@Beanpublic Binding queueaBindingX(@Qualifier("queueA")Queue queueA, @Qualifier("xExchange")DirectExchange xExchange) {return BindingBuilder.bind(queueA).to(xExchange).with("XA");}//声明队列Bttl为40s并绑定到对应的死信交换机@Bean("queueB")public Queue queueB(){Map<String,Object>args=new HashMap<>(3);//声明当前队列绑定的死信交换机args.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);//声明当前队列的死信路由keyargs.put("x-dead-letter-routing-key","YD");//声明队列的TTLargs.put("x-message-ttl",40000);return QueueBuilder.durable(QUEUE_B).withArguments(args).build();}//声明队列B绑定X交换机@Beanpublic Binding queuebBindingX(@Qualifier("queueB")Queue queue1B,@Qualifier("xExchange")DirectExchange xExchange){return BindingBuilder.bind(queue1B).to(xExchange).with("XB");}//声明死信队列QD@Bean("queueD")public Queue queueD(){return QueueBuilder.durable(DEAD_LETTER_QUEUE).build();}//声明死信队列QD绑定关系@Beanpublic Binding deadLetterBindingQAD(@Qualifier("queueD")Queue queueD,@Qualifier("yExchange")DirectExchange yExchange){return BindingBuilder.bind(queueD).to(yExchange).with("YD");}}

消息生产者代码


import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.Date;/***  * @author lenovo* 发送延迟消息* http:/localhost:8080/ttl/sendMsg/嘻嘻嘻*/
@Slf4j
@RequestMapping("/ttl")
@RestController
public class SendMsgController{@Autowiredprivate RabbitTemplate rabbitTemplate;//开始发消息@GetMapping("/sendMsg/{message}")public void sendMsg(@PathVariable String message){log.info("当前时间:{},发送一条信息给两个TTL队列:{}", new Date(), message);rabbitTemplate.convertAndSend("X", "XA", "消息来自ttl为10S的队列: " + message);rabbitTemplate.convertAndSend("X", "XB", "消息来自ttl为40S的队列: " + message);}}

消息消费者代码

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.Date;/*** 队列TTL  消费者*/
@Slf4j
@Component
public class DeadLetterQueueConsumer {@RabbitListener(queues="QD")public void receiveD(Message message, Channel channel) throws IOException {String msg = new String(message.getBody());log.info("当前时间:{},收到死信队列信息{}", new Date().toString(), msg);}}

启动服务发送消息

http://localhost:8080/ttl/sendMsg/嘻嘻嘻

延迟队列优化

新增了一个队列QC,绑定关系如下,该队列不设置TTL时间

配置文件类代码修改

@Configuration
public class TtlQueueConfig {//普通交换机的名称public static final String X_EXCHANGE = "X";//普通队列的名称public static final String QUEUE_A = "QA";public static final String QUEUE_B="QB";//增加普通·队列qcpublic static final String QUEUE_C="QC";..................//声明队列C死信交换机@Bean("queueC")public Queue queueC(){Map<String,Object>args=new HashMap<>(3);//声明当前队列绑定的死信交换机args.put("x-dead-letter-exchange",Y_DEAD_LETTER_EXCHANGE);//声明当前队列的死信路由keyargs.put("x-dead-letter-routing-key","YD");//没有声明TTL属性return QueueBuilder.durable(QUEUE_C).withArguments(args).build();}//声明队列C绑定X交换机@Beanpublic Binding queuecBindingX(@Qualifier("queueC")Queue queue1C,@Qualifier("xExchange")DirectExchange xExchange){return BindingBuilder.bind(queue1C).to(xExchange).with("XC");}

消息生产者代码

@GetMapping("sendExpirationMsg/{message}/{ttlTime}")public void sendMsg (@PathVariable String  message,@PathVariable String ttlTime) {rabbitTemplate.convertAndSend("X", "XC", message, correlationData ->{//发送消息的时候延迟时长correlationData.getMessageProperties().setExpiration(ttlTime);return correlationData;} );log.info("当前时间:{},发送一条时长(}毫秒TTL信息给队列c: {}", new Date(), ttlTime, message);}

发起请求:

http://localhost:8080/ttl/sendExpirationMsg/你好1/20000
http://localhost:8080/ttl/sendExpirationMsg/你好2/2000


看起来似乎没什么问题,但是如果使用在消息属性上设置TTL的方式,消息可能并不会按时“死亡“,因为RabbitMQ只会检查第一个消息是否过期,如果过期则丢到死信队列,如果第一个消息的延时时长很长,而第二个消息的延时时长很短,第二个消息并不会优先得到执行。即队列先进先出的特性,耗时短的消息仍在耗时长的消息之后排队。这个特性的不足可以使用插件进行了弥补。

基于插件实现的延迟队列

如果不能实现在消息粒度上的TTL,并使其在设置的TTL时间及时死亡,就无法设计成一个通用的延时队列。那如何解决呢->rabbitmq_delayed_message_exchange插件(基于插件的延迟队列实现是在交换机部分,所以可以解决上述问题)
官网下载地址
下载好后解压放置到RabbitMQ的插件目录。
linux下是进入RabbitMQ的安装目录下的plgins目录,执行下面命令让该插件生效,然后重

RabbitMQ /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins
rabbitmq-pluginsenablerabbitmq_delayed_message_exchange


代码架构图

新增了一个队列delayed.queue,一个自定义交换机delayed.exchange,绑定关系如下:
配置文件类代码
在我们自定义的交换机中,这是一种新的交换类型,该类型消息支持延迟投递机制消息传递后并不会立即投递到目标队列中,而是存储在 mnesia(一个分布式数据系统)表中,当达到投递时间时,才投递到目标队列中。

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** 基于插件的延迟队列配置*/
@Configuration
public class DelayedQueueConfig {//队列public static final String DELAYED_QUEUE_NAME="delayed.queue";//交换机public static final String DELAYED_EXCHANGE_NAME = "delayed.exchange";public static final String DELAYED_ROUTING_KEY="delayed.routingkey";@Beanpublic Queue delayedQueue(){return new Queue(DELAYED_QUEUE_NAME);}//自定义交换机我们在这里定义的是一个延迟交换机@Beanpublic CustomExchange delayedExchange(){Map<String,Object> args=new HashMap<>();//自定义交换机的类型args.put("x-delayed-type","direct");/***     1.交换机的名称*     2.交换机的类型*     3.是否需要持久化*     4.是否需要自动删除*     5.其他参数*/return new CustomExchange(DELAYED_EXCHANGE_NAME,"x-delayed-message",true,false,args);}//绑定@Beanpublic Binding bindingDelayedQueue(@Qualifier("delayedQueue")Queue queue, @Qualifier("delayedExchange") CustomExchange delayedExchange){return BindingBuilder.bind(queue).to(delayedExchange).with(DELAYED_ROUTING_KEY).noargs();}}

消息生产者代码

/*** 基于插件的消息及延迟*/public static final String DELAYED_EXCHANGE_NAME = "delayed.exchange";public static final String DELAYED_ROUTING_KEY="delayed.routingkey";@GetMapping("sendDelayMsg/{message}/{delayTime}")public void sendMsg(@PathVariable String message,@PathVariable Integer delayTime){rabbitTemplate.convertAndSend(DELAYED_EXCHANGE_NAME,DELAYED_ROUTING_KEY,message,correlationData->{correlationData.getMessageProperties().setDelay(delayTime);return correlationData;});log.info("当前时间:{}, 发送一条延迟{}毫秒的信息给延迟队列{}", new Date(), delayTime, message);}

消息消费者代码

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;import java.util.Date;/*** 消费者,基于插件的延迟消息*/
@Slf4j
@Component
public class DelayQueueConsumer {public static final String DELAYED_QUEUE_NAME = "delayed.queue";//监听消息@RabbitListener(queues=DELAYED_QUEUE_NAME)public void receiveDelayedQueue(Message message) {String msg = new String(message.getBody());log.info("当前时间:{},收到延时队列的消息:{}", new Date().toString(), msg);}}

发起请求:

http://localhost:8080/ttl/sendDelayMsg/come on baby1/20000
http://localhost:8080/ttl/sendDelayMsg/comeonbaby2/2000

第二个消息被先消费掉了,符合预期.

延时队列在需要延时处理的场景下非常有用,使用RabbitMQ来实现延时队列可以很好的利RabbitMQ的特性,如:消息可靠发送、消息可靠投递、死信队列来保障消息至少被消费一次以及未被正确处理的消息不会被丢弃。另外,通过RabbitMQ集群的特性,可以很好的解决单点故障问题,不会因为单个节点挂掉导致延时队列不可用或者消息丢失.
当然,延时队列还有很多其它选择,比如利用Java的DelayQueue,利用Redis的zset,利用Quartz 或者利用kafka的时间轮,这些方式各有特点,看需要适用的场景.

rabbitmq死信队列及延迟队列相关推荐

  1. 【重难点】【RabbitMQ 01】消息队列的作用、主流的消息队列、RabbitMQ 基于什么传输消息、RabbitMQ 模型架构、死信队列和延迟队列

    [重难点][RabbitMQ 01]消息队列的作用.主流的消息队列.RabbitMQ 基于什么传输消息.RabbitMQ 模型架构.死信队列和延迟队列 文章目录 [重难点][RabbitMQ 01]消 ...

  2. 死信队列和延迟队列_在实践中使用延迟队列

    死信队列和延迟队列 通常,在某些情况下,当您有某种工作或作业队列时,有必要不立即处理每个工作项或作业,而是要延迟一些时间. 例如,如果用户单击一个按钮来触发要完成的某项工作,而一秒钟后,用户意识到他/ ...

  3. 【无标题】支付场景常见的死信队列+TTL延迟队列的实现

    支付场景常见的死信队列+TTL延迟队列的实现 有道云笔记https://note.youdao.com/s/8ndbQ5NS 分析:可以发现 ,一个消息随着业务产生后 (这个消息伴随着死信队列发出)经 ...

  4. 消息队列之延迟队列超详细入门教程速看

    一. 延迟队列的应用场景 1.具体应用 关于消息队列我们已经很熟悉了,我们知道在消息队列中可以实现延迟队列效果,那你知道延迟队列有哪些使用场景吗?这里我给大家总结了延迟队列的几个经典使用场景,看看你的 ...

  5. RabbitMq(十二) 借用死信交换机实现延迟队列

    概述:延迟队列即在消息发送后延迟固定时间后再去接受处理,做相应的一些相应. 应用场景举例:在电商购物后,订单支付前发送消息信息,在三分钟之后检查订单是否支付成功,如果支付,则取消订单并库存数量恢复:或 ...

  6. RabbitMq(五) -- 死信队列和延迟队列

    1. 死信 1.1 死信的概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到 queue ...

  7. RabbitMQ(五)死信队列和延迟队列

    1.1 概念 先从概念解释上搞清楚这个定义,死信,顾名思义就是无法被消费的消息,字面意思可以这样理解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consum ...

  8. Rabbitmq超级详细的笔记,包括安装,基本命令,rabbitmq的七种消息模式,以及死信队列,延迟队列,优先级队列和惰性队列的介绍

    RabbitMQ 文章目录 RabbitMQ 1 RabbitMQ介绍 1.1 基本介绍 1.2 RabbitMQ的安装 1.2.1 ubuntu20.04 安装rabbitmq 1.2.2 cent ...

  9. 面试官:RabbitMQ本身不支持延迟队列,那你给我实现一个?

    以下文章来源方志朋的博客,回复"666"获面试宝典 RabbitMQ本身没有延迟队列的支持,但是基于其本身的一些特性,可以做到类似延迟队列的效果:基于死信交换器+TTL. 以下介绍 ...

  10. RabbitMQ(七)延迟队列

    7.1延迟队列的概念 ​ 延时队列,队列内部是有序的,最重要的特性就体现在他的延迟属性上,延时队列中的元素时希望在指定时间到了以后或之前取出和处理,简单来说,延时队列就是用来存放需要在指定时间被处理的 ...

最新文章

  1. 警惕!新版Net Transport(影音传送带)安装有猫腻
  2. 远程为服务器安装Windows 2008 Server
  3. python 在主线程开线程_Python开启线程,在函数中开线程的实例
  4. 鸿蒙系统画饼,任正非说在三年内华为鸿蒙系统即可媲美苹果!真的不是“画饼”?...
  5. 关于Scrum中sprint的规模估算的对话
  6. c#扩展方法奇思妙用高级篇七:“树”通用遍历器
  7. Oracle 10中修改字符集(character set)
  8. python中括号的作用_Python3--中括号[]与冒号:在列表中的作用
  9. 用java自动化访问百度测试_java+eclipse+selenium+百度搜索设置自动化测试
  10. 1个模型横扫40+个SOTA!22位华人共同打造佛罗伦萨模型,一统图像视频文本,含9亿图像-文本对...
  11. Intel Core Enhanced Core架构/微架构/流水线 (12) - 数据预取
  12. FreeBSD 查看USB
  13. leetcode:String to Integer (atoi)
  14. ZYNQ+FPGA读取SD卡BMP图片并通过HDMI显示
  15. 求解鸡兔同笼问题C语言
  16. GitHub上14个屌炸天的Java进阶教程、面试真题项目,建议收藏!
  17. 全球及中国IT外包市场价值评估及投资战略决策报告2021-2027年
  18. HAL库与标准库的理解
  19. 【有利可图网】PS教程:用滤镜打造3D立体文字效果
  20. [c语言]进值转换的详细代码实现(二进制,十进制,十六进制等)

热门文章

  1. HDU 2121 无固定根的最小树形图
  2. 传统数据库的四大分类
  3. 贵高速sign加密算法
  4. oracle 12c sp2 0667,Oracle
  5. Python就业后能拿高薪吗
  6. 20210605 “北京市私立汇佳学校”考点 TOEFL考试有感(无题目回忆 只是有感...)
  7. 第七周 学习记录1--色彩搭配的6大平衡法则
  8. 2023年天津市大学软件学院专升本软件工程专业真题试卷
  9. python——网络爬虫快速入门【数据提取篇】
  10. python 环境下安装geopandas( GDAL, Fiona, pyproj,rtree,shapely)注意版本适配