springboot rabbitmq 之死信队列(延迟消费消息)「建议收藏」

springboot rabbitmq 之死信队列(延迟消费消息)

大家好,又见面了,我是全栈君。

之前探讨了springboot 集成 rabbitmq  以及开启ack模式   

传送门:https://my.oschina.net/u/2948566/blog/1624963

接着该篇 搞一下 死信队列

  • 概念

死信队列 听上去像 消息“死”了     其实也有点这个意思,死信队列  是 当消息在一个队列 因为下列原因:

  1. 消息被拒绝(basic.reject/ basic.nack)并且不再重新投递 requeue=false
  2. 消息超期 (rabbitmq  Time-To-Live -> messageProperties.setExpiration()) 
  3. 队列超载

变成了 “死信” 后    被重新投递(publish)到另一个Exchange   该Exchange 就是DLX     然后该Exchange 根据绑定规则 转发到对应的 队列上  监听该队列  就可以重新消费     说白了 就是  没有被消费的消息  换个地方重新被消费

              生产者   –>  消息 –> 交换机  –> 队列  –> 变成死信  –> DLX交换机 –>队列 –> 消费者

  • springboot rabbitmq 死信队列实践

下面我们模拟一个死信队列的应用场景   消息延时处理

还是以这个项目为基础: https://gitee.com/felord/springboot-message

 项目中 RabbitConfig  死信相关片段:

   /**
     * 死信队列跟交换机类型没有关系 不一定为directExchange  不影响该类型交换机的特性.
     *
     * @return the exchange
     */
    @Bean("deadLetterExchange")
    public Exchange deadLetterExchange() {
        return ExchangeBuilder.directExchange("DL_EXCHANGE").durable(true).build();
    }

    /**
     * 声明一个死信队列.
     * x-dead-letter-exchange   对应  死信交换机
     * x-dead-letter-routing-key  对应 死信队列
     *
     * @return the queue
     */
    @Bean("deadLetterQueue")
    public Queue deadLetterQueue() {
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, "DL_EXCHANGE");
//       x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, "KEY_R");
        return QueueBuilder.durable("DL_QUEUE").withArguments(args).build();
    }

    /**
     * 定义死信队列转发队列.
     *
     * @return the queue
     */
    @Bean("redirectQueue")
    public Queue redirectQueue() {
        return QueueBuilder.durable("REDIRECT_QUEUE").build();
    }

    /**
     * 死信路由通过 DL_KEY 绑定键绑定到死信队列上.
     *
     * @return the binding
     */
    @Bean
    public Binding deadLetterBinding() {
        return new Binding("DL_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "DL_KEY", null);

    }

    /**
     * 死信路由通过 KEY_R 绑定键绑定到死信队列上.
     *
     * @return the binding
     */
    @Bean
    public Binding redirectBinding() {
        return new Binding("REDIRECT_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "KEY_R", null);
    }

说明: 

deadLetterExchange()声明了一个Direct 类型的Exchange (死信队列跟交换机没有关系

deadLetterQueue() 声明了一个队列   这个队列 跟前面我们声明的队列不一样    注入了 Map<String,Object> 参数    下面的概念非常重要   

x-dead-letter-exchange 来标识一个交换机  x-dead-letter-routing-key  来标识一个绑定键(RoutingKey)  这个绑定键 是分配给 标识的交换机的   如果没有特殊指定 声明队列的原routingkey , 如果有队列通过此绑定键 绑定到交换机    那么死信会被该交换机转发到 该队列上  通过监听 可对消息进行消费  

可以打个比方  这个是为主力队员 设置了一个替补   如果主力 “死”了   他的活 替补接手  这样更好理解

deadLetterBinding() 对这个带参队列 进行了 和交换机的规则绑定   等下 消费者 先把消息通过交换机投递到该队列中去   然后制造条件发生“死信” 

redirectBinding() 我们需要给标识的交换机  以及对其指定的routingkey 来绑定一个所谓的“替补”队列 用来监听

 

流程具体是  消息投递到  DL_QUEUE  10秒后消息过期 生成死信    然后转发到 REDIRECT_QUEUE  通过对其的监听  来消费消息     

SendController 增加消费发送接口 

    /**
     * 测试死信队列.
     *
     * @param p the p
     * @return the response entity
     */
    @RequestMapping("/dead")
    public ResponseEntity deadLetter(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
//        声明消息处理器  这个对消息进行处理  可以设置一些参数   对消息进行一些定制化处理   我们这里  来设置消息的编码  以及消息的过期时间  因为在.net 以及其他版本过期时间不一致   这里的时间毫秒值 为字符串
        MessagePostProcessor messagePostProcessor = message -> {
            MessageProperties messageProperties = message.getMessageProperties();
//            设置编码
            messageProperties.setContentEncoding("utf-8");
//            设置过期时间10*1000毫秒
            messageProperties.setExpiration("10000");
            return message;
        };
//         向DL_QUEUE 发送消息  10*1000毫秒后过期 形成死信
        rabbitTemplate.convertAndSend("DL_EXCHANGE", "DL_KEY", p, messagePostProcessor, correlationData);
        return ResponseEntity.ok();
    }

 

监听 REDIRECT_QUEUE 

    /**
     * 监听替补队列 来验证死信.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"REDIRECT_QUEUE"})
    public void redirect(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        log.debug("dead message  10s 后 消费消息 {}",new String (message.getBody()));
    }

 

测试死信队列接口

springboot rabbitmq 之死信队列(延迟消费消息)「建议收藏」

不出意外  消息会在发出10秒后 才被消费     一下信息证实了这一猜测

springboot rabbitmq 之死信队列(延迟消费消息)「建议收藏」

 

相关源码:https://gitee.com/felord/springboot-message      希望大家点个赞

转载于:https://my.oschina.net/10000000000/blog/1626278

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107694.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm安装使用教程_vcenter安装

    pycharm安装使用教程_vcenter安装1.PyCharm介绍PyCharm是一种PythonIDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如,调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制等等。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业Web开发。同时支持GoogleAppEngine,更酷的是,PyCharm支持IronPython!这些功能在先进代码分析程序的支持下,使PyCharm成为Python专业开发人员和刚起步人员使

    2022年8月27日
    0
  • HTML+CSS实现导航条及下拉菜单[通俗易懂]

    HTML+CSS实现导航条及下拉菜单[通俗易懂]html+css实现下拉菜单

    2022年5月18日
    76
  • rstrip python_Python strip()、split()和rstrip()方法

    rstrip python_Python strip()、split()和rstrip()方法1.Pythonstrip()语法描述:Pythonstrip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符。返回值:返回值是返回移除字符串头尾指定的字符生成的新字符串示例:a1=”00000123hello_world12300000000″printa1.strip(“0”)#去除首尾字符0a2…

    2022年10月31日
    0
  • 天翼云IP_天翼网关ip地址

    天翼云IP_天翼网关ip地址在很多应用场景中,需要在云平台中搭建高可用集群,就这需要用到虚拟IP地址功能。今天就来谈一谈虚拟IP地址及它的应用场景。一、高可用集群在谈虚拟IP地址前,我们先了解一下什么叫高可用集群。高可用集群(HighAvailabilityCluster),或者叫故障转移集群(FailoverCluster),它是指通过集群软件,将几台服务器组合为一个集群系统提供服务,这些服务器中同一时间内一般只有一台在提供服务(称之为主节点或者Master节点),其…

    2022年10月20日
    0
  • EL表达式详解

    EL表达式详解一、EL表达式简介EL全名为ExpressionLanguage。EL主要作用:1、获取数据EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域中检索java对象、获取数

    2022年7月2日
    18
  • 正则提取字符串中的数字_正则表达式忽略空格python

    正则提取字符串中的数字_正则表达式忽略空格pythonpython从字符串中提取数字使用正则表达式,用法如下:##总结##^匹配字符串的开始。##$匹配字符串的结尾。##\b匹配一个单词的边界。##\d匹配任意数字。##\D匹配任意非数字字符。##x?匹配一个可选的x字符(换言之,它匹配1次或者0次x字符)。##x*匹配0次或者多次x字符。##x+匹配1次或者多次x字符。…

    2022年10月3日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号