1.例外資訊
版本說明:
mq服務器版本:4.9.2
java客戶端:4.9.2
1.1 RemotingTimeoutException: invokeSync call timeout
Caused by: org.apache.rocketmq.remoting.exception.RemotingTimeoutException: invokeSync call timeout
at org.apache.rocketmq.remoting.netty.NettyRemotingClient.invokeSync(NettyRemotingClient.java:375)
at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1367)
at org.apache.rocketmq.client.impl.MQClientAPIImpl.getTopicRouteInfoFromNameServer(MQClientAPIImpl.java:1357)
at org.apache.rocketmq.client.impl.factory.MQClientInstance.updateTopicRouteInfoFromNameServer(MQClientInstance.java:622)
... 6 more
1.2 RemotingTooMuchRequestException: sendDefaultImpl call timeout
org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQProducerImpl.java:683)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1391)
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.send(DefaultMQProducerImpl.java:1335)
at org.apache.rocketmq.client.producer.DefaultMQProducer.send(DefaultMQProducer.java:336)
at hh.simple.SyncSendMsg.main(SyncSendMsg.java:35)
2.處理方法
新建自定義MyProducer 類,繼承DefaultMQProducer,重寫cloneClientConfig,新增實體化MyProducer物件時用到的構造方法
MyProducer 代碼如下:
public class MyProducer extends DefaultMQProducer {
public MyProducer(String producerGroup) {
super(producerGroup);
}
@Override
public ClientConfig cloneClientConfig() {
ClientConfig config = super.cloneClientConfig();
config.setMqClientApiTimeout(super.getMqClientApiTimeout());
return config;
}
}
main方法(發送訊息的代碼如下):
public static void main(String[] args) throws MQClientException {
DefaultMQProducer producer = new MyProducer("test-group");
// 設定超時時間
producer.setMqClientApiTimeout(1000*10);
producer.setNamesrvAddr("localhost:9876");
producer.start();
System.out.printf("SyncProducer Started.%n");
// topic, tags, body
Message msg = new Message("test-topic","test-tag", "測驗訊息1234".getBytes(Charset.forName("utf-8")));
try {
// 此處的timeout是等待broker回應資訊的時長,設定為10s,以防超時
SendResult result = producer.send(msg, 1000*10);
System.out.printf("%s%n", result);
} catch (RemotingException e) {
e.printStackTrace();
} catch (MQBrokerException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
3.排查處理程序
根據報錯資訊,可以定位到報錯原始碼位置:
MQClientAPIImpl的getTopicRouteInfoFromNameServer方法的1367行
容易推斷出,是因為此方法執行時間超過了給定的timeoutMillis,于是便回傳上層,追究引數是從哪里來的:
查找此方法在哪里呼叫,經排查發現在
MQClientInstance的updateTopicRouteInfoFromNameServer方法中622行,
那么問題來了,這個clientConfig是從哪里來的呢?請繼續往下看
經排查,這個引數是從MQClientInstance的建構式傳入的
進一步排查,在MQClientManager的getOrCreateMQClientInstance方法的52行呼叫了上述建構式并傳入由clientConfig.cloneClientConfig()回傳的ClientConfig物件,那么這個clientConfig到底是啥,繼續往下:
進一步排查,在DefaultMQProducerImpl中start方法的201行,原來是defaultMQProducer,應該就是我們new出來的DefaultMQProducer物件,為了證實繼續往下:
看看是哪個地方呼叫了此建構式,繼續往下:
果然,就是我們的DefaultMQProducer物件,所以之前的"那么這個clientConfig到底是啥"",答案就是:clientConfig為DefaultMQProducer物件,
那么知道clientConfig就是DefaultMQProducer物件后,再回到標記一處:進入cloneClientConfig方法
就是重新new了一個ClientConfig物件,把配置引數進行一一賦值,仔細觀察這里面沒有mqClientApiTimeout這個引數,意思就是除了這里面賦值外的其他引數全部會恢復為ClientConfig類中的引數默認值,
即:就算我們進行如下操作,在producer中設定了mqClientApiTimeout引數,經過上述操作后,配置也會被清空
DefaultMQProducer producer = new DefaultMQProducer("test-group");
// 設定超時時間
producer.setMqClientApiTimeout(1000*10);
故我們只有重寫cloneClientConfig方法,將mqClientApiTimeout引數設定進新的ClientConfig物件中,到此問題得到解決,這就是為什么要繼承DefaultMQProducer并重寫cloneClientConfig方法的原因,
對于1.2的RemotingTooMuchRequestException: sendDefaultImpl call timeout報錯,呼叫含超時引數的方法即可,具體排查可進入下述send方法逐步查看原始碼,
// 此處的timeout是等待broker回應資訊的時長,設定為10s,以防超時
SendResult result = producer.send(msg, 1000*10);
System.out.printf("%s%n", result);
重新運行main方法,超時例外不再出現,若還報超時,可以嘗試將超時時間增加,
DefaultMQPushConsumer也可按照上述方法進行設定即可
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/439224.html
標籤:其他