Retry mechanism of rocket message

In the process of sending and consuming messages, there may be errors, such as network abnormalities, etc. If errors occur, an error retry is required. This kind of message retry needs to be divided into two types, namely the producer side retry and the consumer side. Retry.


Retry on the
producer side The message on the producer side failed, that is, the message sent by the Producer to MQ was not sent successfully. For example, the network jitter caused the producer to fail to send the message to MQ.

SyncProducer.java

package com.woodie.rocketmq.error;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

public class SyncProducer {
    // 不好演示,看源码出现了特定的异常就会进行重试
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("HAOKE_IM");
        producer.setNamesrvAddr("192.168.142.128:9876");
        //消息发送失败时,重试3次
        producer.setRetryTimesWhenSendFailed(3);
        producer.start();
        String msgStr = "用户A发送消息给用户B";
        Message msg = new Message("haoke_im_topic","SEND_MSG", msgStr.getBytes(RemotingHelper.DEFAULT_CHARSET));

        // 发送消息,并且指定超时时间
        SendResult sendResult = producer.send(msg, 1000);

        System.out.println("消息状态:" + sendResult.getSendStatus());
        System.out.println("消息id:" + sendResult.getMsgId());
        System.out.println("消息queue:" + sendResult.getMessageQueue());
        System.out.println("消息offset:" + sendResult.getQueueOffset());
        System.out.println(sendResult);
        producer.shutdown();
    }
}

 

Retry on the
consumer side There are two types of failures on the consumer side, one is exception and the other is timeout.
The exception
message arrived at the consumer normally, and as a result, the consumer experienced an exception and the processing failed. For example, the deserialization fails, the message data itself cannot be processed (for example
, the phone bill is recharged, the mobile phone number of the current message is cancelled, and the recharge is not possible), etc.
The status of the message (source code):

package org.apache.rocketmq.client.consumer.listener;

public enum ConsumeConcurrentlyStatus {
    CONSUME_SUCCESS,
    RECONSUME_LATER;

    private ConsumeConcurrentlyStatus() {
    }
}

As you can see, the status of the message is divided into success or failure. What if the returned status is failed? You can see this information in the log of starting the broker:

INFO main - messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

This means that if the message consumption fails, the message will be retried after 1s, 5s, and 10s, and will not be retried until 2h. In fact, sometimes you don’t need to retry so many times, usually 3~5 times. At this time, you can control the number of retries through msg.getReconsumeTimes().

ConsumerDemo.java

package com.woodie.rocketmq.error;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
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.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.io.UnsupportedEncodingException;
import java.util.List;
public class ConsumerDemo {
    // 测试时先启动这个类,然后找一个生产者发送消息
    public static void main(String[] args) throws Exception {
        // 定义一个消费者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("woodie");
        // 设置访问的地址
        consumer.setNamesrvAddr("192.168.142.128:9876");
        // 订阅topic,接收此Topic下的所有消息
        consumer.subscribe("my-topic", "*");
        //
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
                                                            ConsumeConcurrentlyContext context) {
                for (MessageExt msg : msgs) {
                    try {
                        System.out.println(new String(msg.getBody(), "UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("收到消息->" + msgs);
                if(msgs.get(0).getReconsumeTimes() >= 3){
                    // 重试3次后,不再进行重试
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }

                // 返回失败
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
        });
        consumer.start();
    }
}

Timeout, for
example, due to network reasons, the message does not go from MQ to the consumer at all, then RocketMQ will continue to try to send this message until it is successfully sent!
That is to say, the server does not receive the feedback of the message, and it is neither a success nor a failure. At this time, it is defined as a timeout.

Guess you like

Origin blog.csdn.net/qq_26896085/article/details/104981570