RocketMQ(5)--- RocketMQリトライ機構

RocketMQの再試行メカニズム

:再試行メッセージは2つに分割されているメッセージの送信プロデューサーの再試行個人消費の再試行メッセージを

、プロデューサーの再試行終了

プロデューサーの目的は手段を再試行:MQメッセージにプロデューサーが送信されない、ネットワークがプロデューサーMQ不良の原因にメッセージを送信するなど。

コードを見てください:

@Slf4j
public class RocketMQTest {
    /**
     * 生产者组
     */
    private static String PRODUCE_RGROUP = "test_producer";
  
    public static void main(String[] args) throws Exception {
        //1、创建生产者对象
        DefaultMQProducer producer = new DefaultMQProducer(PRODUCE_RGROUP);
        //设置重试次数(默认2次)
        producer.setRetryTimesWhenSendFailed(3000);
        //绑定name server
        producer.setNamesrvAddr("74.49.203.55:9876");
        producer.start();
        //创建消息
        Message message = new Message("topic_family", ("小小今年3岁" ).getBytes());
        //发送 这里填写超时时间是5毫秒 所以每次都会发送失败
        SendResult sendResult = producer.send(message,5);
        log.info("输出生产者信息={}",sendResult);
    }
}

超时重试 インターネットのために、言ったタイムアウト例外は、文が間違って再試行するすべてのその恐ろしい考えるので、私は記事がタイムアウト例外を再試行しますので、多くの人がテストまたはソースを見に行かなかったんと言う確認しました。

私は通常、確かに報告されますタイムアウト例外によると、5ミリ秒タイムアウトの上ですので、私は、問題を発見したが、最終的に次の例外を報告しましたが、私は、再試行および3000の再試行を設定しますが、出力誤差時間レポート

明らかにそれはレベルではありません。しかし、テストは再試行の回数に関係なく、私が設定した回数の、異常なほぼすべての時間を報告したことがわかりました。

org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout

この疑問の後、私は彼が実現しなかった、元に行ってきました。

   /**
     * 说明 抽取部分代码
     */
    private SendResult sendDefaultImpl(Message msg, final CommunicationMode communicationMode, final SendCallback sendCallback, final long timeout) {
        
        //1、获取当前时间
        long beginTimestampFirst = System.currentTimeMillis();
        long beginTimestampPrev ;
        //2、去服务器看下有没有主题消息
        TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
        if (topicPublishInfo != null && topicPublishInfo.ok()) {
            boolean callTimeout = false;
            //3、通过这里可以很明显看出 如果不是同步发送消息 那么消息重试只有1次
            int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
            //4、根据设置的重试次数,循环再去获取服务器主题消息
            for (times = 0; times < timesTotal; times++) {
                MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName);
                beginTimestampPrev = System.currentTimeMillis();
                long costTime = beginTimestampPrev - beginTimestampFirst;
                //5、前后时间对比 如果前后时间差 大于 设置的等待时间 那么直接跳出for循环了 这就说明连接超时是不进行多次连接重试的
                if (timeout < costTime) {
                    callTimeout = true;
                    break;

                }
                //6、如果超时直接报错
                if (callTimeout) {
                    throw new RemotingTooMuchRequestException("sendDefaultImpl call timeout");
                }
        }
    }

これは明らかにソースを以下で見ることができます

  1. それがある場合に异步发送のみ1試行の回数
  2. 同期超时异常也是不会再去重试
  3. リトライリトライが行くためにforループで発生するので、再試行するのではなく、随時、すぐに再試行された場合。

本当に習うより慣れろ!


二、消費者側の再試行

消費者側はより興味深いですが、また、実際の開発プロセスでは、我々は考慮すべきである消費者側で、再試行してください。

失敗した消費者側は事態の2種類に分け、されるExceptionTimeout

1、例外

@Slf4j
@Component
public class Consumer {
    /**
     * 消费者实体对象
     */
    private DefaultMQPushConsumer consumer;
    /**
     * 消费者组
     */
    public static final String CONSUMER_GROUP = "test_consumer";
    /**
     * 通过构造函数 实例化对象
     */
    public Consumer() throws MQClientException {
        consumer = new DefaultMQPushConsumer(CONSUMER_GROUP);
        consumer.setNamesrvAddr("47.99.203.55:9876;47.99.203.55:9877");
        //订阅topic和 tags( * 代表所有标签)下信息
        consumer.subscribe("topic_family", "*");
        //注册消费的监听 并在此监听中消费信息,并返回消费的状态信息
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            //1、获取消息
            Message msg = msgs.get(0);
            try {
                //2、消费者获取消息
                String body = new String(msg.getBody(), "utf-8");
                //3、获取重试次数
                int count = ((MessageExt) msg).getReconsumeTimes();
                log.info("当前消费重试次数为 = {}", count);
                //4、这里设置重试大于3次 那么通过保存数据库 人工来兜底
                if (count >= 2) {
                    log.info("该消息已经重试3次,保存数据库。topic={},keys={},msg={}", msg.getTopic(), msg.getKeys(), body);
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
                //直接抛出异常
                throw new Exception("=======这里出错了============");
                //return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            } catch (Exception e) {
                e.printStackTrace();
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
        });
        //启动监听
        consumer.start();
    }
}

ここでは、コードの意味が明確にされてい:例外をスローするためのイニシアチブをとる、3倍以上あれば、それを再試行していきませんが、レコードはすべての詳細を明らかにし、手でデータベースに保存されます。

営業成績を見てください

注意 消費者と生産者を再試行違いがある、二つの主があります

1、デフォルトのリトライ回数:製品のデフォルト値は2倍で、消費者のデフォルトは16です

2、再試行間隔:製品はすぐに再試行され、消費者は、一定の時間間隔がありますそれはようである1S,5S,10S,30S,1M,2M····2H再試行。

2、タイムアウト

说明ここでタイムアウトタイムアウト例外は、それが消費RocketMQ、すなわち無の状態に戻りませんでした何らかの理由で、買収のニュースを指し、真の意味で、それが参照ではありませんreturn ConsumeConcurrentlyStatus.CONSUME_SUCCESSreturn ConsumeConcurrentlyStatus.RECONSUME_LATER

だから、RocketMQが送られていたであろう、メッセージが送信されないと思いますそれは単にメッセージを消費者に送信されると信じていませんので、それは確かに消費者ではありません。

このテストを行うのは非常に簡単です。

        //1、消费者获得消息
        String body = new String(msg.getBody(), "utf-8");
        //2、获取重试次数
        int count = ((MessageExt) msg).getReconsumeTimes();
        log.info("当前消费重试次数为 = {}", count);
        //3、这里睡眠60秒
        Thread.sleep(60000);
       log.info("休眠60秒 看还能不能走到这里。topic={},keys={},msg={}", msg.getTopic(), msg.getKeys(), body);
        //返回成功
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;

取得すると再試行の回数消費電流= 0をした後、プロセスをオフにしますプロセスを再起動してから、まだニュースの一部を取得することができます

consumer消费者  当前消费重试次数为 = 0
休眠60秒 看还能不能走到这里。topic=topic_family,keys=1a2b3c4d5f,msg=小小今年3岁




只要自己变优秀了,其他的事情才会跟着好起来(上将2)

おすすめ

転載: www.cnblogs.com/qdhxhz/p/11117379.html