消息手动确认模式的几点说明

  • 监听的方法内部必须使用channel进行消息确认,包括消费成功或消费失败

  • 如果不手动确认,也不抛出异常,消息不会自动重新推送(包括其他消费者),因为对于rabbitmq来说始终没有接收到消息消费是否成功的确认,并且Channel是在消费端有缓存的,没有断开连接

  • 如果rabbitmq断开,连接后会自动重新推送(不管是网络问题还是宕机)

  • 如果消费端应用重启,消息会自动重新推送

  • 如果消费端处理消息的时候宕机,消息会自动推给其他的消费者

  • 如果监听消息的方法抛出异常,消息会按照listener.retry的配置进行重发,但是重发次数完了之后还抛出异常的话,消息不会重发(也不会重发到其他消费者),只有应用重启后会重新推送。因为retry是消费端内部处理的,包括异常也是内部处理,对于rabbitmq是不知道的(此场景解决方案后面有)

  • spring.rabbitmq.listener.retry配置的重发是在消费端应用内处理的,不是rabbitqq重发

  • 可以配置MessageRecoverer对异常消息进行处理,此处理会在listener.retry次数尝试完并还是抛出异常的情况下才会调用,默认有两个实现:

    • RepublishMessageRecoverer:将消息重新发送到指定队列,需手动配置,如:
    1. @Bean
    2. public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
    3. return new RepublishMessageRecoverer(rabbitTemplate, "exchangemsxferror", "routingkeymsxferror");
    4. }
    • RejectAndDontRequeueRecoverer:如果不手动配置MessageRecoverer,会默认使用这个,实现仅仅是将异常打印抛出,源码如下:
  1. public class RejectAndDontRequeueRecoverer implements MessageRecoverer {
  2.  
  3. protected Log logger = LogFactory.getLog(RejectAndDontRequeueRecoverer.class);
  4.  
  5. @Override
  6. public void recover(Message message, Throwable cause) {
  7. if (this.logger.isWarnEnabled()) {
  8. this.logger.warn("Retries exhausted for message " + message, cause);
  9. }
  10. throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message);
  11. }
  12.  
  13. }
  • 可以通过给队列(Queue)绑定死信队列,使用nack反馈给mq,会将消息转发到死信队列里面,此种方式需要自己在消费消息的方法内部将异常处理掉

  1. //声明队列,并给队列增加x-dead-letter-exchange和x-dead-letter-routing-key参数,用于指定死信队列的路由和routingKey
  2. @Bean
  3. public Queue queue(){
  4. Map<String, Object> args = new HashMap<String, Object>();
  5. args.put("x-dead-letter-exchange",IntegralConstant.DEAD_EXCHANGE_NAME);
  6. args.put("x-dead-letter-routing-key",IntegralConstant.DEAD_ROUTING_KEY);
  7. return new Queue(IntegralConstant.QUEUE_NAME, true, false, false, args);
  8. }
  9.  
  10. //消息确认时使用nack,并且requeue参数传false
  11. channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
  • 消息变成死信有以下几种情况:

    • 消息被拒绝(basic.reject/ basic.nack)并且requeue=false
    • 消息TTL过期(参考:RabbitMQ之TTL(Time-To-Live 过期时间))
    • 队列达到最大长度

总结

  • 消息监听内必须使用channel对消息进行确认,不管是确认消费成功还是确认消费失败
  • 消息监听内的异常处理有两种方式:
    • 内部catch后直接处理,然后使用channel对消息进行确认
    • 配置RepublishMessageRecoverer将处理异常的消息发送到指定队列专门处理或记录
  • 监听的方法内抛出异常貌似没有太大用处。因为抛出异常就算是重试也非常有可能会继续出现异常,当重试次数完了之后消息就只有重启应用才能接收到了,很有可能导致消息消费不及时。当然可以配置RepublishMessageRecoverer来解决,但是万一RepublishMessageRecoverer发送失败了呢。。那就可能造成消息消费不及时了。所以即使需要将处理出现异常的消息统一放到另外队列去处理,个人建议两种方式:
    • catch异常后,手动发送到指定队列,然后使用channel给rabbitmq确认消息已消费
    • 给Queue绑定死信队列,使用nack(requque为false)确认消息消费失败

rabbit mq 手动重试机制的更多相关文章

  1. Rabbit MQ 消息确认和持久化机制

    一:确认种类 RabbitMQ的消息确认有两种.一种是消息发送确认,用来确认生产者将消息发送给交换器,交换器传递给队列的过程中消息是否成功投递.发送确认分为两步,一是确认是否到达交换器,二是确认是否到 ...

  2. RabbitMq手动确认时的重试机制

    本文转载自RabbitMq手动确认时的重试机制 消息手动确认模式的几点说明 监听的方法内部必须使用channel进行消息确认,包括消费成功或消费失败 如果不手动确认,也不抛出异常,消息不会自动重新推送 ...

  3. 分布式消息中间件Rabbit Mq的了解与使用

    MQ(消息队列)作为现代比较流行的技术,在互联网应用平台中作为中间件,主要解决了应用解耦.异步通信.流量削锋.服务总线等问题,为实现高并发.高可用.高伸缩的企业应用提供了条件. 目前市面比较流行的消息 ...

  4. Rabbit MQ config文件解析

    Rabbit MQ config文件解析 tcp_listeners:用于监听AMQP连接的端口或主机名/对(不带TLS),默认端口:5672 2.numtcpacceptors :将接受TCP侦听器 ...

  5. rabbit MQ 消息队列

    为什么会需要消息队列(MQ)? 一.消息队列概述消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ...

  6. celery rabbit mq 详解

    Celery介绍和基本使用 Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, ...

  7. RocketMQ-消费重试机制

    介绍: RocketMQ的消息重试及时分为两种,一种是Producer端重试,一种是Consume端重试. 1.Producer端重试 : 1.1消息发没发成功,默认情况下是3次重试. 2.Consu ...

  8. SpringCloud | FeignClient和Ribbon重试机制区别与联系

    在spring cloud体系项目中,引入的重试机制保证了高可用的同时,也会带来一些其它的问题,如幂等操作或一些没必要的重试. 今天就来分别分析一下 FeignClient 和 Ribbon 重试机制 ...

  9. Rocket重试机制,消息模式,刷盘方式

    一.Consumer 批量消费(推模式) 可以通过 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 这里需要分为2种情况 Consumer端先 ...

随机推荐

  1. 微信小程序-强制手机端更新

    小程序的更新机制 开发者在管理后台发布新版本的小程序之后,如果某个用户本地有小程序的历史版本,此时打开的可能还是旧版本.微信客户端会有若干个时机去检查本地缓存的小程序有没有更新版本,如果有则会静默更新 ...

  2. Java时区问题

    Java时区相关 时间格式 UTC是以原子时计时,更加精准,适应现代社会的精确计时.不过一般使用不需要精确到秒时,视为等同.GMT是前世界标准时,UTC是现世界标准时.每年格林尼治天文台会发调时信息, ...

  3. Redis面试篇 -- Redis常见性能问题和解决方案?

    master最好不要做任何的持久化工作,如RD内存快照或者AOF日志文件: 如果数据比较重要,某个slave开始AOF备份数据,策略设置为每秒同步1次: 为了主从复制的速度和连接的稳定性,master ...

  4. react学习之弹出层

    react的弹出层不同于以往的DOM编程,我们知道,在DOM中,弹出层事件绑定在对应的节点上即可,但是在react中,往往只能实现父子之间的传递控制,显然,弹出层的层级不符合此关系. 在这里我们需要使 ...

  5. WEB UI分布式自动化测试框架

    Github地址: https://github.com/zhangweixu/Autotest.git

  6. mybatis入门视频总结

    1.基础知识 2. 原生态jdbc问题总结 3.mybatis是什么 4.工程结构 5.SqlMapConfig.xml文件 6.sqlmap 包下新建user.xml文件(namespace,par ...

  7. qt 自定义控件窗口提升

  8. 几种常见的css布局_l流体布局、圣杯布局、双飞翼布局

    1.流体布局: <!DOCTYPE html><html> <head> <meta charset="utf-8"> <ti ...

  9. python - selenium模块简介

    为什么要使用Selenium? 很多浏览器渲染页面的方式都很难找出其规律, 但是利用Selenium来驱动加载网页就可以直接拿到javaScript渲染后的结果了, 不需要再担心其相关的加密系统 声明 ...

  10. 2019年FJNU低编赛 G题(dfs博弈)

    ###题目链接### 题目大意: 有一个 0 ~ n+1 的数轴,Alice 站在 0 点处,Bob 站在 n+1 点处.在 1 ~ n 上各有着权值. Alice 每次向右移动 1 格或两格 ,Bo ...