一、顺序消息的消费重试
对于顺序消息,当 Consumer 消费消息失败后,为了保证消息的顺序性,其会自动不断地进行消息重试,直到消费成功。消费重试默认间隔时间为 1000 毫秒。重试期间应用会出现消息消费被阻塞的情况。
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("cg");
// 顺序消息消费失败的消费重试时间间隔,单位毫秒,默认为1000,其取值范围为[10, 30000]
consumer.setSuspendCurrentQueueTimeMillis(100);
由于对顺序消息的重试是无休止的,不间断的,直至消费成功,所以,对于顺序消息的消费,务必要保证应用能够及时监控并处理消费失败的情况,避免消费被永久性阻塞。
注意:顺序消息没有发送失败重试机制,但具有消费失败重试机制
二、无序消息的消费重试
对于无序消息(普通消息、延时消息、事务消息),当 Consumer 消费消息失败时,可以通过设置返回状态达到消息重试的效果。不过需要注意,无序消息的重试只对集群消费方式生效,广播消费方式不提供失败重试特性。即对于广播消费,消费失败后,失败消息不再重试,继续消费后续消息。
三、消费重试次数与间隔
对于无序消息集群消费下的重试消费,每条消息默认最多重试 16 次,但每次重试的间隔时间是不同的,会逐渐变长。每次重试的间隔时间如下表。
![](https://files.mdnice.com/user/27110/e929c99b-312f-4bf0-8333-1442998a191a.png)
若一条消息在一直消费失败的前提下,将会在正常消费后的第 4 小时 46 分 后进行第 16 次重试。若仍然失败,则将消息投递到 死信队列
修改消费重试次数
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("cg");
// 修改消费重试次数
consumer.setMaxReconsumeTimes(10);
对于修改过的重试次数,将按照以下策略执行
- 若修改值小于 16,则按照指定间隔进行重试
- 若修改值大于 16,则超过 16 次的重试时间间隔均为 2 小时
对于 Consumer Group,若仅修改了一个 Consumer 的消费重试次数,则会应用到该 Group 中所有其它 Consumer 实例。若出现多个 Consumer 均做了修改的情况,则采用覆盖方式生效。即最后被修改的值会覆盖前面设置的值。
四、重试队列
对于需要重试消费的消息,并不是 Consumer 在等待了指定时长后再次去拉取原来的消息进行消费,而是将这些需要重试消费的消息放入到了一个特殊 Topic 的队列中,而后进行再次消费的。这个特殊的队列就是重试队列。
当出现需要进行重试消费的消息时,Broker 会为每个消费组都设置一个 Topic 名称为%RETRY%consumerGroup@consumerGroup
的重试队列。
1)这个重试队列是针对消息才组的,而不是针对每个 Topic 设置的(一个 Topic 的消息可以让多个消费者组进行消费,所以会为这些消费者组各创建一个重试队列)
2)只有当出现需要进行重试消费的消息时,才会为该消费者组创建重试队列
![](https://files.mdnice.com/user/27110/635819d1-d531-407c-95f4-c2a99d16d018.png)
注意,消费重试的时间间隔与延时消费 的延时等级 十分相似,除了没有延时等级的前两个时间外,其它的时间都是相同的
Broker 对于重试消息的处理是通过延时消息实现的。先将消息保存到 SCHEDULE_TOPIC_XXXX 延迟队列中,延迟时间到后,会将消息投递到%RETRY%consumerGroup@consumerGroup
重试队列中。
五、消费重试配置方式
![](https://files.mdnice.com/user/27110/0274755c-ca93-4088-b5bf-e74b18beca40.png)
集群消费方式下,消息消费失败后若希望消费重试,则需要在消息监听器接口的实现中明确进行如下三种方式之一的配置:
- 方式 1:返回 ConsumeConcurrentlyStatus.RECONSUME_LATER(推荐)
- 方式 2:返回 Null
- 方式 3:抛出异常
六、消费不重试配置方式
![](https://files.mdnice.com/user/27110/3888ee9f-dd09-4e85-862c-6355810e1f52.png)
集群消费方式下,消息消费失败后若不希望消费重试,则在捕获到异常后同样也返回与消费成功后的相同的结果,即 ConsumeConcurrentlyStatus.CONSUME_SUCCESS,则不进行消费重试。