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 过期时间, 超出标准重试次数或者到期的消息,进入死信队列等待处理
版权归原作者 毁人不倦zy 所有, 如有侵权,请联系我们删除。