本文转载自RabbitMq手动确认时的重试机制

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

  • 监听的方法内部必须使用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. protected Log logger = LogFactory.getLog(RejectAndDontRequeueRecoverer.class);
  3. @Override
  4. public void recover(Message message, Throwable cause) {
  5. if (this.logger.isWarnEnabled()) {
  6. this.logger.warn("Retries exhausted for message " + message, cause);
  7. }
  8. throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message);
  9. }
  10. }
  • 可以通过给队列(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. //消息确认时使用nack,并且requeue参数传false
  10. 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)确认消息消费失败

RabbitMq手动确认时的重试机制的更多相关文章

  1. 使用rabbitmq手动确认消息的,定时获取队列消息实现

    描述问题 最近项目中因为有些数据,需要推送到第三方系统中,因为数据会一直增加,并且需要与第三方系统做相关交互. 相关业务 本着不影响线上运行效率的思想,我们将增加的消息放入rabbitmq,使用另一个 ...

  2. [转载]rabbitmq可靠发送的自动重试机制

    转载地址http://www.jianshu.com/p/6579e48d18ae http://www.jianshu.com/p/4112d78a8753 接这篇 在上文中,主要实现了可靠模式的c ...

  3. rabbitmq 不发送ack消息如何处理:rabbitmq可靠发送的自动重试机制

    转载地址:http://www.jianshu.com/p/6579e48d18ae http://www.jianshu.com/p/4112d78a8753 接这篇 在上文中,主要实现了可靠模式的 ...

  4. jmeter-利用While Controller控制器实现接口报错时的重试机制

    预期功能:在jmter脚本报错的时候重试,最多重试5次 1.添加While Controller 2.添加请求 3.添加断言,在断言不符合预期的时候加上代码:vars.put("status ...

  5. 要做重试机制,就只能选择 DelayQueue ?其实 RabbitMQ 它上它也行!

    原文链接:要做重试机制,就只能选择 DelayQueue ?其实 RabbitMQ 它上它也行! 一.场景 最近研发一个新功能,后台天气预警:后台启动一条线程,定时调用天气预警 API,查询现有城市的 ...

  6. rabbit mq 手动重试机制

    消息手动确认模式的几点说明 监听的方法内部必须使用channel进行消息确认,包括消费成功或消费失败 如果不手动确认,也不抛出异常,消息不会自动重新推送(包括其他消费者),因为对于rabbitmq来说 ...

  7. RabbitMQ消息确认机制

    文章目录 1. 事务机制2. Confirm模式2.1 生产者2.1.1 普通Confirm模式2.1.2 批量Confirm模式2.1.3 异步Confirm模式2.2 消费者3. 其他 消费者如何 ...

  8. 【独家】完美解决appium安装app时,需要手动确认安装的问题

    appium初始化driver时,如果未安装该app会先进行安装,安装时,很多安卓手机都会弹框,需要手动确认安装. 如小米的机器, 这是个头疼的问题,之前在网上找遍了,只有通过adb去点相对坐标成功了 ...

  9. rabbitmq学习(八) —— 可靠机制上的“可靠”

    接着上一篇,既然已经有了手动ack.confirm机制.return机制,还不够吗? 以下博文转自https://www.jianshu.com/p/6579e48d18ae和https://my.o ...

随机推荐

  1. CentOS7.X安装英伟达显卡采坑之路

    1.系统信息 操作系统版本:CentOS7.X 显卡版本:英伟达 Tesla P100 其他软件包安装信息: CUDA 9.0 CUDNN 7.4.2.24 lightgbm 2.2.X Boost ...

  2. 漫画 | CPU战争40年,真正的王者终于现身!

    上个世纪70年代,内存又慢又贵, 程序员得想尽一切办法节省内存. 那个时代的编译器也比较差劲 所以,70年代的程序员几乎都写得一手好汇编. 为了帮助程序员写好汇编,这个时候的CPU也有意把指令集做了增 ...

  3. Pytest(16)随机执行测试用例pytest-random-order

    前言 通常我们认为每个测试用例都是相互独立的,因此需要保证测试结果不依赖于测试顺序,以不同的顺序运行测试用例,可以得到相同的结果. pytest默认运行用例的顺序是按模块和用例命名的 ASCII 编码 ...

  4. 一文弄懂-BIO,NIO,AIO

    目录 一文弄懂-BIO,NIO,AIO 1. BIO: 同步阻塞IO模型 2. NIO: 同步非阻塞IO模型(多路复用) 3.Epoll函数详解 4.Redis线程模型 5. AIO: 异步非阻塞IO ...

  5. k8s~kubectl常用命令

    查看所有 pod 列表, -n 后跟 namespace, 查看指定的命名空间 kubectl get pod kubectl get pod -n kube kubectl get pod -o w ...

  6. Java一些概念

    1.Java先编译后解释 同一个.class文件在不同的虚拟机会得到不同的机器指令(Windows和Linux的机器指令不同),但是最终执行的结果却是相同的. 2.JDK包含JRE,JRE包含JVM, ...

  7. codeforces578C. Weakness and Poorness

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  8. 详解Go语言I/O多路复用netpoller模型

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 本文使用的go的源码15.7 可以从 Go 源码目录结构和对应代码文件了解 Go 在不同 ...

  9. MySQL 回表查询 & 索引覆盖优化

    回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...

  10. hdu 5874

    On an isolated island, lived some dwarves. A king (not a dwarf) ruled the island and the seas nearby ...