org.apache.rocketmq.client.exception.MQClientException: No route info of this topic
笔者最近在使用rocketmq时,使用部署在docker中的rocketmq就会报“org.apache.rocketmq.client.exception.MQClientException: No route info of this topic”异常,win10本地启动同版本的rocketmq release库没有任何问题,搜索了许久仍然没有找到问题,关于这个问题,部分原因在笔者,笔者没有完全按照http://rocketmq.apache.org/docs/simple-example/ 里面的demo引入下面的rocketmq-client依赖,而是引入的rocketmq-spring-boot-starter这个依赖,示例代码如下:
@Test
public void send() throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException, MQBrokerException {
//Instantiate with a producer group name.
DefaultMQProducer producer = new
DefaultMQProducer("my-group1");
//rocketmq nameserver地址
producer.setNamesrvAddr("172.21.52.27:9876");
producer.start();
Message msg = new Message("test" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ ").getBytes("utf-8") /* Message body */
);
//Call send message to deliver message to one of brokers.
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
//Shut down once the producer instance is not longer in use.
producer.shutdown();
}
经过跟踪发现标红部分的代码根本没有起作用,为什么没起作用呢,下面看下DefaultMQProducer的构造方法:
public DefaultMQProducer(String producerGroup, RPCHook rpcHook) {
this.log = ClientLogger.getLog();
this.createTopicKey = "TBW102";
this.defaultTopicQueueNums = 4;
this.sendMsgTimeout = 3000;
this.compressMsgBodyOverHowmuch = 4096;
this.retryTimesWhenSendFailed = 2;
this.retryTimesWhenSendAsyncFailed = 2;
this.retryAnotherBrokerWhenNotStoreOK = false;
this.maxMessageSize = 4194304;
this.traceDispatcher = null;
this.producerGroup = producerGroup;
//创建DefaultMQProducerImpl对象
this.defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
}
//发送消息
public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
return this.defaultMQProducerImpl.send(msg);
}
从send方法以及DefaultMQProducer的构造方法可以看出,引入rocketmq-spring-boot-starter引入后导致MQClientInstance实例被提前创建,提前创建使用的是application.yml文件中配置:
rocketmq:
name-server: 127.0.0.1:9876
producer:
group: my-group
该配置里面使用的就是127.0.0.1 而不是docker中部署的nameserver地址,虽然使用producer.setNamesrvAddr(“172.21.52.27:9876”)设置了rocketmq nameserver地址,但是其实是无效的,具体原因可以在MQClientManager类getAndCreateMQClientInstance方法查看,
public MQClientInstance getAndCreateMQClientInstance(ClientConfig clientConfig, RPCHook rpcHook) {
String clientId = clientConfig.buildMQClientId();
MQClientInstance instance = (MQClientInstance)this.factoryTable.get(clientId);
if (null == instance) {
instance = new MQClientInstance(clientConfig.cloneClientConfig(), this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);
MQClientInstance prev = (MQClientInstance)this.factoryTable.putIfAbsent(clientId, instance);
if (prev != null) {
instance = prev;
log.warn("Returned Previous MQClientInstance for clientId:[{}]", clientId);
} else {
log.info("Created new MQClientInstance for clientId:[{}]", clientId);
}
}
return instance;
}
由于引入rocketmq-spring-boot-starter导致getAndCreateMQClientInstance过早被创建,所以后续同一clientId不再创建MQClientInstance而使用最初创建的实例!
产生问题的原因在于最初application.proerties配置的是127.0.0.1:9876 虽然application.yml配对了地址,但是由于properties文件优先级比yaml文件高,导致一直使用的是127.0.0.1:9876这个错误地址,但是本地没有开启rocketmq服务,所以一直报”org.apache.rocketmq.client.exception.MQClientException: No route info of this topic”这个异常,搜索了很多最终都没有解决问题,最终单步调试解决了该问题。
PS:
1、是rocketmq的错误提示信息不够细,如果报connection exception之类的异常,也许早就解决了这个问题,但是却报出了很多场景都可能出现的”org.apache.rocketmq.client.exception.MQClientException: No route info of this topic“这个错误
2、引入rocketmq-spring-boot-starter以来时不要使用DefaultMQProducer发送信息
还没有评论,来说两句吧...