飞不高 发表于 昨天 21:01

RabbitMQ---TTL与死信

(一)TTL

1.TTL概念

 TTL又叫过期时间
RabbitMQ可以对队列和消息设置TTL,当消息到达过期时间还没有被消耗时就会自动删除
注:这里我们说的对队列设置TTL,是对队列上的消息设置TTL并不是对队列自己,不是说队列过期时间到了,队列被删除,而是消息到达此队列后会给他设定一个过期时间,这个时间到了,消息会删除,不是队列删除(如果同时此消息自己带有TTL过期时间,按短的来)
2.设置消息的TTL

  那我们说可以对队列和消息设置TTL
  那我们现在来先写对每条消息设置TTL(就是针对每一条消息设置消息的expiration参数,单元是毫秒)
那我们来看生产者代码(这里设置文件不需要去更改)
@RequestMapping("ttl")
    public String TTLPro(){
      String s1="ttl test";
      Message message=new Message(s1.getBytes(StandardCharsets.UTF_8));
      message.getMessageProperties().setExpiration("10000");
      RabbitTemplate.convertAndSend(Constants.TTL_EXCHANGE,"ttl",message);
      return "发送成功";
    }   我们来看征象,我这里设置过期时间为10s,按理说到达队列后,如果10s钟还没有被消耗掉,就会自动过期 
https://i-blog.csdnimg.cn/direct/d282e3e0fd07400fbcdbe8be2043e285.png
10s后 
https://i-blog.csdnimg.cn/direct/8b872ceaeafd456d8bb9b715c0a93e22.png
 如果我们不设置TTL就表现消息不会过期,如果设置为0的化,就表现除非此时可以直接将消息给消耗者,否者就会被丢弃
 3.设置队列的TTL

  设置队列的TTL是比较简单的,但是注意,我们队列如果存在的话,我们是不可以直接改代码,然后更改队列的设置信息的,同时交换机也是这样,如果我们想改,可以再声明个队列,大概把队列先删了再创建(此时队列上的消息会丢失)
https://i-blog.csdnimg.cn/direct/a6a70c93749f4a3b9db572907ce867c8.png
设置队列过期时间,只需要在队列上设置ttl属性就可以,我这里设置了5s
https://i-blog.csdnimg.cn/direct/8cf2158ced3e442b83a1e4d3b7347f65.png
https://i-blog.csdnimg.cn/direct/35ea0d339deb4554a0c9b5cea3fdc5a4.png
此时我们队列的特性就又多了个TTL 
 然后我们继承向接口发送消息https://i-blog.csdnimg.cn/direct/a06a9f97ecd44a84aec7b8c862654788.png
5s后就酿成了(真的是5s 哄人是g)
https://i-blog.csdnimg.cn/direct/1b5ce30b83a242218a3402318da3a7c9.png
4.两者区别 

 设置队列TTL属性的方法,一旦消息过期,就会立刻从队列中删除
 设置消息TTL的方法,一旦消息过期(且不是队列中第一个消息),消息并不会立刻删除,而是在要发送给消耗者之进步行判定,如果过期了再删
 那我们就有疑问了,这是为什么呢?   本质上,是为了提高性能,因为设置队列的过期时间,他们消息的最长存在时间就是队列的过期时间,所有消息的存在时间都小于等于队列过期时间,所以此时队列中已过期的元素大部分都在队列头部,RabbitMQ只需要定期从队头开始扫描是否有过期消息即可
  而设置消息TTL,每条消息的过期时间都不同,如果想要删除所有过期时间,就需要扫描整个队列,很影响性能,所以不如等到用到了此消息,再判定是否过期,如果过期了再删除
(二)死信

1.死信概念

 死信就是因为一些原因(包括消息过期,消息被拒绝接收,队列到达最大长度)无法被消耗的消息。
 那既然有这些无法被处理的信息,那一定就有存储他们的队列,有队列就要有交换机,那么这个队列就叫做死信队列(DLQ),这个交换机就叫死信交换机(DLX)
 本质上与正常的交换机和队列没什么区别
https://i-blog.csdnimg.cn/direct/7b7e515336d549249ea4340f6b701b82.png
消息酿成死信后,会被发送到死信交换机,然后由死信交换机绑定到死信队列中
2.代码演示

起首我们要声明一个死信队列和死信交换机举行绑定,哪至于正常的队列,我们就用刚刚的TTL为5的队列吧
   @Bean("ttlExchange")
    public Exchange ttlExchange(){
      return ExchangeBuilder.directExchange(Constants.TTL_EXCHANGE).durable(true).build();
    }
    @Bean("ttlQueue")
    public Queue ttlQueue(){
      return QueueBuilder.durable(Constants.TTL_QUEUE).ttl(5000)
                .deadLetterExchange(Constants.DEAD_EXCHANGE).deadLetterRoutingKey("dead")
                .build();
    }
    @Bean("ttlBind")
    public Binding ttlBind(@Qualifier("ttlExchange") Exchange ackExchange,@Qualifier("ttlQueue") Queue queue){
      return BindingBuilder.bind(queue).to(ackExchange).with("ttl").noargs();
    }
    @Bean("deadExchange")
    public Exchange deadExchange(){
      return ExchangeBuilder.directExchange(Constants.DEAD_EXCHANGE).durable(true).build();
    }
    @Bean("deadQueue")
    public Queue deadQueue(){
      return QueueBuilder.durable(Constants.DEAD_QUEUE).build();
    }
    @Bean("deadBind")
    public Binding deadBind(@Qualifier("deadExchange") Exchange ackExchange,@Qualifier("deadQueue") Queue queue){
      return BindingBuilder.bind(queue).to(ackExchange).with("dead").noargs();
    } 然后我们发送消息等待5s看一下
https://i-blog.csdnimg.cn/direct/cad6b07c822640c5bd944ba6daae977c.png 
然后我们看看刚才绑定死信交换机的谁人队列特征https://i-blog.csdnimg.cn/direct/bfc90046975b4fd9b70708c463690d8a.png 
我们发现又多了两个特征
那验证完TTL过后,我们来看消息被拒绝的情况
起首我们要把消息确认模式改成手动确认,然后拒绝接收消息
@RabbitListener(queues = Constants.TTL_QUEUE)
    public void ListenerQueue2(Message message,Channel channel) throws IOException {
      long Tag=message.getMessageProperties().getDeliveryTag();
      try {
            System.out.println("接收到消息: "+ new String(message.getBody())+" TagID: "
                  +Tag);
            int num=3/0;   //模拟失败
            channel.basicAck(Tag,false);
            System.out.println("处理完成");
      }catch (Exception e){
            channel.basicReject(Tag,false);
      }
    } 然后我们调用接口,看死信队列,我们发现确实多了一条死信消息 
https://i-blog.csdnimg.cn/direct/1014657abc2f4f969e6ce3fa33cc84c3.png 
那第三种产存亡信的消息是,队列满了,那我们就需要更改一下我们队列 
@Bean("ttlQueue")
    public Queue ttlQueue(){
      return QueueBuilder.durable(Constants.TTL_QUEUE).ttl(5000)
                .deadLetterExchange(Constants.DEAD_EXCHANGE)
                .deadLetterRoutingKey("dead")
                .maxLength(5l)
                .build();
    } https://i-blog.csdnimg.cn/direct/f7353bffe97647da8f17680f3bf39ca0.png 
此时我们注意我们要的是long范例,如果传错了会给我们报错的
https://i-blog.csdnimg.cn/direct/04bcbd8d8aab42b2b3fa296de49f2c99.png
那我们再来看这个队列
https://i-blog.csdnimg.cn/direct/14542111d6504d568acf0967f6da4131.png 我们发现又多了一个特征
我们到此已经给队列设置5个特征了,我们来分别看一下
1)D:设置队列为长期化的
2)TTL:设置队列的过期时间
3)Lim:设置队列的最大长度
4)DLX:设置了死信交换机
5)DLK:设置了死信RoutingKey
3.死信面试题

死信概念,死信来源,死信场景
前两个我们都说过了,这里主要说一下死信的应用场景
比如我们用户付出订单,付出体系会给我们订单体系返回当前订单的付出状态
 为了保障付出信息不丢失,需要使用死信队列机制,当消息消耗异常时,会放到死信队列中(有可能存在用户付出,但是消息没有被消耗大概异常拒绝的情况),此时我们放到死信队列中,再对这个数据举行处理(可能是人工确认)
还有一些应用场景包括:
消息丢弃,直接丢弃这些无法处理的消息,避免他们占用体系资源
日志收集:将死信消息作为日志收集,用于后续分析和定位


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: RabbitMQ---TTL与死信