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試行の回数 - 同期
超时异常也是不会再去重试
。 - リトライリトライが行くためにforループで発生するので、再試行するのではなく、随時、すぐに再試行された場合。
本当に習うより慣れろ!!!
二、消費者側の再試行
消費者側はより興味深いですが、また、実際の開発プロセスでは、我々は考慮すべきである消費者側で、再試行してください。
失敗した消費者側は事態の2種類に分け、されるException
とTimeout
。
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_SUCCESS
かreturn 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)