失败重试机制
当消费者出现异常后,消息会不断进行重新投递,然后消费者从新消费,然后再异常,在投递,会无限循环,导致mq的消息处理飙升,带来不必要的压力
我可以利用spring的retry机制,在消费者出现异常时利用本地重试,而不是无限制的投递到队列
这是在消费者配置的mq重试机制和生产者重试机制很像,主要是listener代表消费者
之前的template代表生成者。
用java代码如何实现
消费者
生成者
MQ控制台
启动消费者看结果
消息被消费掉了,说明不会一直被投递,并无限循环
看idea的控制台
最后会抛出异常Retries exhausted for message 意思是重试耗尽,并且消息直接会丢弃
然后他的规律和生产者的规律是一样的都是间隔时间*乘子 ,大家会奇怪为什么我最后一次重试的时间是10秒呢这是不对因为有一个最大的max-interval: 10000 # 重试最大间隔时间 就是间隔时间*乘子不能超过,并且如果我们没有设置,他会默认给10000ms
但是有个问题,如果重试多次依然失败如何解决呢!
其实有3中失败的处理策略
rejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢弃消息。默认就是这种方式
ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入列
RepulishMessageRRecoverer:重试耗尽后,将失败的消息投递到指定的交换机
如下图
如果我们发送者通过通过交换机发送给队列,然后消费者监听这个队列,但是这时候如果期间出现错误,导致重试机制出错,我们设置一个error.direct的交换机和error.queue队列。将失败的消息扔到这个队列中,将来有一个监听这个队列的消费者,来监听这个队列,并进行人为处理这些错误信息。
用java代码如何实现第三种方案
首先先创建一个ErrorConfiguration类
然后创建error交换机,error队列,然后进行绑定
接下来创建失败策略
从图中可以看到MessageRecoverer接口的实现类
其中有ImmediateRequeueMessageRecoverer 重试耗尽仍队列
RepublishMessageRecoverer重试耗尽仍指定队列
RejectAndDontRequeueRecoverer 重试耗尽直接丢掉
然后我们实现的是第三种,第三种需要传参,但是传参的是AmqpTemplate类型,但是我们一直使用的是rabbitTemplate,也可以传,因为他们是父子,
可以看到他需要传递3个参数
第一参数是rabbitmqTemplate,第二个参数是交换机,第三个参数是key
发送消息结果
我们可以看到
Republishing failed message to exchange 'error.direct' with routing key error 他会抛出这种异常
然后我们到控制台上看错误信息
可以看到这个队列中有错误信息的日志,接下来就是人工处理