Spring Cloud Stream消费失败后的处理策略(四):重新入队(RabbitMQ)
应用场景
之前我们已经通过《Spring Cloud Stream消费失败后的处理策略(一):自动重试》一文介绍了Spring Cloud Stream默认的消息重试功能。本文将介绍RabbitMQ的binder提供的另外一种重试功能:重新入队。
动手试试
准备一个会消费失败的例子,可以直接沿用前文的工程,也可以新建一个,然后创建如下代码的逻辑:
@EnableBinding(TestApplication.TestTopic.class) @SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } @RestController static class TestController { @Autowired private TestTopic testTopic; /** * 消息生产接口 * * @param message * @return */ @GetMapping("/sendMessage") public String messageWithMQ(@RequestParam String message) { testTopic.output().send(MessageBuilder.withPayload(message).build()); return "ok"; } } /** * 消息消费逻辑 */ @Slf4j @Component static class TestListener { private int count = 1; @StreamListener(TestTopic.INPUT) public void receive(String payload) { log.info("Received payload : " + payload + ", " + count); throw new RuntimeException("Message consumer failed!"); } } interface TestTopic { String OUTPUT = "example-topic-output"; String INPUT = "example-topic-input"; @Output(OUTPUT) MessageChannel output(); @Input(INPUT) SubscribableChannel input(); } }
内容很简单,既包含了消息的生产,也包含了消息消费。消息消费的时候主动抛出了一个异常来模拟消息的消费失败。
在启动应用之前,还要记得配置一下输入输出通道对应的物理目标(exchange或topic名)、并设置一下分组,比如:
spring.cloud.stream.bindings.example-topic-input.destination=test-topic spring.cloud.stream.bindings.example-topic-input.group=stream-exception-handler spring.cloud.stream.bindings.example-topic-input.consumer.max-attempts=1 spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.requeue-rejected=true spring.cloud.stream.bindings.example-topic-output.destination=test-topic
完成了上面配置之后,启动应用并访问localhost:8080/sendMessage?message=hello
接口来发送一个消息到MQ中了,此时可以看到程序不断的抛出了消息消费异常。这是由于这里我们多加了一个配置:spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.requeue-rejected=true
。在该配置作用之下,消息消费失败之后,并不会将该消息抛弃,而是将消息重新放入队列,所以消息的消费逻辑会被重复执行,直到这条消息消费成功为止。
深入思考
在完成了上面的这个例子之后,可能读者会有下面两个常见问题:
问题一:之前介绍的Spring Cloud Stream默认提供的默认功能(spring.cloud.stream.bindings.example-topic-input.consumer.max-attempts)与本文所说的重入队列实现的重试有什么区别?
Spring Cloud Stream默认提供的默认功能只是对处理逻辑的重试,它们的处理逻辑是由同一条消息触发的。而本文所介绍的重新入队史通过重新将消息放入队列而触发的,所以实际上是收到了多次消息而实现的重试。
问题二:如上面的例子那样,消费一直不成功,这些不成功的消息会被不断堆积起来,如何解决这个问题?
对于这个问题,我们可以联合前文介绍的DLQ队列来完善消息的异常处理。
我们只需要增加如下配置,自动绑定dlq队列:
spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.auto-bind-dlq=true
然后改造一下消息处理程序,可以根据业务情况,为进入dlq队列增加一个条件,比如下面的例子:
@StreamListener(TestTopic.INPUT) public void receive(String payload) { log.info("Received payload : " + payload + ", " + count); if (count == 3) { count = 1; throw new AmqpRejectAndDontRequeueException("tried 3 times failed, send to dlq!"); } else { count ++; throw new RuntimeException("Message consumer failed!"); } }
设定了计数器count,当count为3的时候抛出AmqpRejectAndDontRequeueException
这个特定的异常。此时,当只有当抛出这个异常的时候,才会将消息放入DLQ队列,从而不会造成严重的堆积问题。
代码示例
本文示例读者可以通过查看下面仓库的中的stream-exception-handler-4
项目:
如果您对这些感兴趣,欢迎star、follow、收藏、转发给予支持!
以下专题教程也许您会有兴趣
本文首发:http://blog.didispace.com/spring-cloud-starter-finchley-7-5/
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
vue中$refs的用法及作用详解
一般来讲,获取DOM元素,需document.querySelector(".input1")获取这个dom节点,然后在获取input1的值。 但是用ref绑定之后,我们就不需要在获取dom节点了,直接在上面的input上绑定input1,然后$refs里面调用就行。 然后在javascript里面这样调用:this.$refs.input1 这样就可以减少获取dom节点的消耗了 用法如下: HTML: <div id="app"> <input type="text" ref="input1"/> <button @click="add">添加</button> </div> JS: <script> new Vue({ el: "#app", methods:{ add:function(){ this.$refs.input1.value ="test"; //this.$refs.input1 减少获取dom节点的消耗 } } }) </script> 前端全栈学习交流圈:866109386,面...
- 下一篇
基于RabbitMQ解决微信大量并发回调的问题(微信产品服务端工程师值得看)
前言 大量粉丝的公众号已经有非常多了,数百万数千万的都很多,再加上很多微信开放平台,导致接收的微信回调非常多,如:关注/取消关注,获取地理位置,发消息,向用户推送模板消息,点击菜单,扫描带参二维码。这么多场景都会导致微信回调,若单纯使用Tomcat,Undertow,apache之类的Web容器去处理,使用资源成本比较大,而且微信要求在5s内进行回复直接异步处理也需要很多机器才处理得来。可以选择使用些高性能IO框架去解决 如果:smart-io, tio, netty, swoole之类去增加吞吐量,但是这样增加了学习成本和维护成本。我之前写过一篇文章是用Redis来解决的解决模板消息回调的困扰, 但是死循环会长期占用一条RUNNABLE线程,比较浪费cpu资源,可以优化成用分布式锁+rangeAll降低循环频率从而减轻负载,这次我要介绍的是使用RabbitMQ去处理(Nginx + Lua + RabbitMQ)。 准备工作 搭建RabbitMQ集群,我有个小伙伴写了篇博客,现在分享一下: RabbitMQ集群原理和部署 SpringBoot整合RabbitMQ Lua连接Rabbi...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题