RocketMQ 消费重试简介

本文介绍了RocketMQ的消费重试机制,包括消费重试的两种场景:网络异常和消费异常。在消费异常时,RocketMQ不会无限重试,而是按照延迟等级逐级增加重试间隔。当达到一定重试次数后,消息会被投递到死信队列。实际生产中,通常会在重试一定次数后将消息存入数据库,由专门程序或人工处理。文中还给出了Spring整合RocketMQ的消费重试代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消费重试

什么是消费重试

当消息发送到Broker成功 ,在被消费者消费时如果消费者没有正常消费 ,此时消息会重试消费。消费重试存在两种场景 :

场景1:消息没有被消费者接收 ,比如消费者与broker存在网络异常。此种情况消息会一直被消费重试。

场景2:当消息已经被消费者成功接收 ,但是在进行消息处理时出现异常 ,消费端无法向Broker返回成功 ,这种情况下 RocketMQ会不断重试。

问题:针对第二种消费重试的场景 ,borker是怎么知道重试呢 ?

消费者在消费消息成功会向broker返回成功状态,否则会不断进行消费重试。

处理策略

问题:当消息在消费时出现异常 ,此时消息被不断重试消费。 RocketMQ会一直重试消费吗 ?

答案是不会的

消息会按照延迟消息的延迟时间等级 ( 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h ) 从第3级开始重试 ,每试一次如果还不成功则延迟等级加1。

比如 :一条消息消费失败 ,等待10s(第3级)进行重试 ,如果还没有被成功消费则延迟等级加1 ,即按第4级别延迟等 待 ,等30s继续进行重试 ,如此进行下去 ,直到重试16次。

当重试了16次还未被成功消费将会投递到死

### RocketMQ手动重试机制实现方式 RocketMQ 提供了多种消息重试机制,其中既包括内置的自动重试功能,也支持开发者通过编程的方式实现手动重试。以下是基于 JavaRocketMQ 手动重试机制的具体实现方法。 #### 1. 配置生产者的重试参数 在 RocketMQ 中,可以通过设置 `DefaultMQProducer` 的属性来控制消息发送失败后的重试行为。虽然这是自动重试的一部分,但在某些情况下也可以作为手动重试的基础逻辑。 ```java import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message; public class ManualRetryExample { public static void main(String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer("manual_retry_group"); producer.setNamesrvAddr("localhost:9876"); // 设置 NameServer 地址 producer.setMaxReconsumeTimes(3); // 设置最大重试次数[^4] producer.start(); Message msg = new Message("TopicTest", "TagA", ("Hello RocketMQ").getBytes()); try { producer.send(msg); } catch (Exception e) { System.out.println("Message send failed, retry manually."); manualRetry(producer, msg); } producer.shutdown(); } } ``` #### 2. 实现手动重试函数 如果需要完全掌控重试过程,可以编写一个独立的方法用于处理消息的手动重试。以下是一个简单的例子: ```java private static void manualRetry(DefaultMQProducer producer, Message message) { int maxRetries = 5; // 自定义的最大重试次数 for (int i = 0; i < maxRetries; i++) { try { Thread.sleep((long) Math.pow(2, i) * 1000); // 使用指数退避算法等待时间增加 producer.send(message); System.out.printf("Message sent successfully after %d retries.%n", i + 1); return; } catch (Exception e) { System.err.printf("Attempt %d to resend the message failed.%n", i + 1); } } System.err.println("All attempts to resend the message have failed."); } ``` 上述代码实现了带指数退避的时间间隔增长策略,每次重试之间的延迟会逐渐变长,从而减少对系统的压力。 #### 3. 处理消费者端的消息重复消费 除了生产者侧的手动重试外,在消费者端也需要考虑消息可能被多次投递的情况。为了防止业务逻辑因重复消费而出现问题,通常建议设计 **幂等性** 或记录已处理过的消息 ID。 ```java import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.common.message.MessageExt; public class IdempotentConsumer implements MessageListenerConcurrently { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for (MessageExt msg : msgs) { String messageId = msg.getMsgId(); // 获取唯一的消息ID if (!isDuplicateMessage(messageId)) { // 判断是否已经处理过该消息 processBusinessLogic(msg.getBody()); // 如果未处理则执行业务逻辑 markAsProcessed(messageId); // 记录此消息已被成功处理 } else { System.out.println("This is a duplicate message and will be ignored."); } } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } private boolean isDuplicateMessage(String messageId) { // 查询数据库或其他存储介质判断消息是否已经被处理 return false; } private void markAsProcessed(String messageId) { // 将消息标记为已处理状态 } private void processBusinessLogic(byte[] body) { // 执行具体的业务逻辑 } } ``` 以上代码展示了如何通过检查消息 ID 来避免重复消费的问题[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清河大善人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值