死信队列小结

        死信队列是RabbitMQ中非常重要的一个特性。简单理解,他是RabbitMQ对于未能正常消费的消息进行的 一种补救机制。死信队列也是一个普通的队列,同样可以在队列上声明消费者,继续对消息进行消费处理。 对于死信队列,在RabbitMQ中主要涉及到几个参数

重点:核心就在这里:

x-dead-letter-exchange: mirror.dlExchange   对应的死信交换机

x-dead-letter-routing-key: mirror.messageExchange1.messageQueue1 死信交换机routingkey
x-message-ttl:3000 消息过期时间

durable: true 持久化,这个是必须的。

如果依然不知道在哪里设置,看下图:创建一个队列的时候有参数可以设置

在这里,x-dead-letter-exchange指定一个交换机作为死信交换机,然后x-dead-letter-routing-key指定交 换机的RoutingKey。而接下来,死信交换机就可以像普通交换机一样,通过RoutingKey将消息转发到对应 的死信队列中。

目录

1、何时会产生死信

2、死信队列的配置方式

3、关于参数x-dead-letter-routing-key

4、如何确定一个消息是不是死信

5、基于死信队列实现延迟队列


1.何时会产生死信

有以下三种情况,RabbitMQ会将一个正常消息转成死信:

一:消息被消费者确认拒绝。消费者把requeue参数设置为false,也就是不重新入队,并且在消费后,向RabbitMQ返回 拒绝。channel.basicReject或者channel.basicNack。

二:消息达到预设的TTL时限还一直没有被消费。

三:消息由于队列已经达到最长长度限制而被丢掉。

TTL即最长存活时间 Time-To-Live 。消息在队列中保存时间超过这个TTL,即会被认为死亡。死亡的消 息会被丢入死信队列,如果没有配置死信队列的话,RabbitMQ会保证死了的消息不会再次被投递,并 且在未来版本中,会主动删除掉这些死掉的消息。 设置TTL有两种方式,一是通过配置策略指定,另一种是给队列单独声明TTL

策略配置方式 - Web管理平台配置 或者 使用指令配置 60000为毫秒单位 在声明队列时指定 - 同样可以在Web管理平台配置,也可以在代码中配置:

Map<String, Object> args = new HashMap<String, Object>();

args.put("x-message-ttl", 60000);

channel.queueDeclare("myqueue", false, false, false, args);

2、死信队列的配置方式

RabbitMQ中有两种方式可以声明死信队列,一种是针对某个单独队列指定对应的死信队列。另一种就是以 策略的方式进行批量死信队列的配置。 针对多个队列,可以使用策略方式,配置统一的死信队列。

rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"my-dlx"}' --apply-to queues

针对队列单独指定死信队列的方式主要是之前提到的三个属性。

channel.exchangeDeclare("some.exchange.name", "direct");

Map<String, Object> args = new HashMap<String, Object>();

args.put("x-dead-letter-exchange", "some.exchange.name");

channel.queueDeclare("myqueue", false, false, false, args);

这些参数,也可以在RabbitMQ的管理页面进行配置。另外,你会注意到,在对队列进行配置时,只有Classic经典队列和Quorum仲裁队列才能配置死信队列, 而目前Stream流式队列,并不支持配置死信队列。

3、关于参数x-dead-letter-routing-key

死信在转移到死信队列时,他的Routing key 也会保存下来。但是如果配置了x-dead-letter-routing-key这 个参数的话,routingkey就会被替换为配置的这个值。 另外,死信在转移到死信队列的过程中,是没有经过消息发送者确认的,所以并不能保证消息的安全性。

4、如何确定一个消息是不是死信

消息被作为死信转移到死信队列后,会在Header当中增加一些消息。在官网的详细介绍中,可以看到很多 内容,比如时间、原因(rejected,expired,maxlen)、队列等。然后header中还会加上第一次成为死信的三个 属性,并且这三个属性在以后的传递过程中都不会更改。

x-first-death-reason

x-first-death-queue

x-first-death-exchange

5、基于死信队列实现延迟队列

其实从前面的配置过程能够看到,所谓死信交换机或者死信队列,不过是在交换机或者队列之间建立一种 死信对应关系,而死信队列可以像正常队列一样被消费。他与普通队列一样具有FIFO的特性。对死信队列的 消费逻辑通常是对这些失效消息进行一些业务上的补偿

RabbitMQ中,是不存在延迟队列的功能的,而通常如果要用到延迟队列,就会采用TTL+死信队列的方 式来处理。

最后,用代码实现一个延时队列的功能:Springboot +rabbitmq

配置类:



@Configuration
public class DeadLetterMsg {

    @Bean
    public Queue orderQueue(){
        Map<String,Object> params = new HashMap<>();
        params.put("x-dead-letter-exchange", MyConstants.DEAD_LETTER_EXCHANGE);
        params.put("x-dead-letter-routing-key",MyConstants.DEAD_KEY);
        params.put("x-message-ttl",30000);
        return new Queue(MyConstants.ORDER_QUEUE,true,false,false,params);
    }

    @Bean
    public DirectExchange orderDirectExchange(){
        return new DirectExchange(MyConstants.ORDER_EXCHANGE);
    }

    @Bean
    public Binding orderBinding(){
        return BindingBuilder.bind(orderQueue()).to(orderDirectExchange()).with(MyConstants.ORDER_KEY);
    }

    @Bean
    public Queue deadQueue(){
        return new Queue(MyConstants.DEAD_LETTER_QUEUE,true,false,false);
    }

    @Bean
    public DirectExchange deadDirectExchange(){
        return new DirectExchange(MyConstants.DEAD_LETTER_EXCHANGE);
    }

    @Bean
    public Binding deadBinding(){
        return BindingBuilder.bind(deadQueue()).to(deadDirectExchange()).with(MyConstants.DEAD_KEY);
    }
}

发送


@RestController
@Api(value = "自己学习rabbitmq",tags = "学习mq动手")
public class XssProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate ;


    @RequestMapping(value = "/sendOrder",method = RequestMethod.GET)
    @ApiOperation(value="订单",notes="sendTopic")
    @ApiImplicitParam(name="msg",value="要发送的信息",defaultValue = "你好,订单")
    public void sendOrder(String msg){

        int random = new Random().nextInt();
        rabbitTemplate.send(MyConstants.ORDER_EXCHANGE,MyConstants.ORDER_KEY
                ,new Message(("订单信息No:123456" +random).getBytes(StandardCharsets.UTF_8)));
    }
}


消费死信队列:

@Component
public class DeadConsumer {

    @RabbitListener(queues = {MyConstants.DEAD_LETTER_QUEUE})
    public void receiveDeadLetterQueue(String message){
        System.out.println(" 死信队列中的消息为:" + message);
    }
}

运行代码就会发现30s后会收到之前发送到orderQueue的信息。注意:这30s中内orderQueue别被消费了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值