RabbitMQ 消费端异常重复循环小记

RabbitMQ 消费端异常

背景

测试项目消费者功能,因为随意输入的message,导致消费端转对象时报错,此时很离谱的事就出现了,消费端一直在循环 消费消>报错->消费. 问题点也能想的来,因为默认是自动应答,异常了相当于是没有应答,然后就一直异常重新抛回队列进行投递.

思路

1.将抛异常的地方干掉,自己处理异常的机制,这样每次都是自动应答

​ 显而易见这样就解决了,但是相当于报异常的时候自己要去写方案去处理,否则这条消息就丢了,因为MQ认为消息已经是消费成功了

2.try catch需要处理的异常,直接抛出来,交给MQ,到上限进入死信队列

spring:
  rabbitmq:
    listener:
      simple:
        default-requeue-rejected: true # 不丢弃
        retry:
          enabled: true # 开启消费者进行重试
          max-attempts: 5 # 最大重试次数
          initial-interval: 3000 # 重试时间间隔   

这种方式需要配置最大重试次数,MQ在尝试足够次数后,这条消息就不会再被处理了,如果是因为网络抖动等不可抗力原因,那么这种方式是有效的,只能说是无能为力的失败,但是如果是因为业务处理抛出来的异常,那不管执行几次都不会成功,相当于消费失败了.

这里有个default-requeue-rejected: true其实跟这个没关系,主要是靠消费重试来解决的,因为默认的就是true,如果只设置default-requeue-rejected: false那么效果就是只会处理一次,异常了就是异常了.

然后在前面的基础上如果有死信队列那就入死信队列.

3.配置消息过期时间,这样时间到期就会直接进入死信队列

这种方式有三种配置方式

1. 消息过期时间 每个消息有自己单独的过期时间,如果指定时间内没有被消费,则会自动过期对应    message.expiration
2. 队列消息过期时间  每个消息过期时间进入队列的过期时间是一致的,到期则会过期 (x-message-ttl)
3. 指定队列的过期时间,对象是队列,将队列删除了.消息自然全部都过期了 (x-expires)
   前提是当前队列没有消费者,也没有被重新声明,并且没有使用channel.basicGet调,如果在过期时间内有消费者,在消费者断开之后会重置过期时间

但是会有一点,RabbitMQ只会对队列头部的消息进行过期淘汰。如果单独给消息设置TTL,先入队列的消息过期时间 如果设置比较长,后入队列的设置时间比较短。会造成消息不会及时地过期淘汰,导致消息的堆积

4.设置死信队列

暂略

总结

1. 最好是有死信队列托底
2. 先把能知道出错的地方都catch住, catch里看是自行处理还是抛出异常交给MQ
3. 不确定的地方那就让他重试也就是配置default-requeue-rejected为true,一定次数后,进入死信队列
4. 如果需要设置成手动应答的形式那更好,我们知道什么时候能处理异常,什么时候能返回ack
5. 如果消息配置了过期时间,那到时间就回到死信队列中去,不管是什么机制的异常处理
6. 死信队列最好有相关逻辑的处理方案,要不然无脑推就会嘣爆炸

所以这里根据业务采用了直接抛出异常的形式,重试次数5,生产者发送消息的时候并设置Message.expiration 过期时间, 超出标准重试次数或者到期的消息,进入死信队列等待处理

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值