org.apache.rocketmq.client.exception.MQClientException: No route info of this topic

╰半夏微凉° 2023-06-19 11:29 47阅读 0赞

笔者最近在使用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这个依赖,示例代码如下:

  1. @Test
  2. public void send() throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException, MQBrokerException {
  3. //Instantiate with a producer group name.
  4. DefaultMQProducer producer = new
  5. DefaultMQProducer("my-group1");
  6. //rocketmq nameserver地址
  7. producer.setNamesrvAddr("172.21.52.27:9876");
  8. producer.start();
  9. Message msg = new Message("test" /* Topic */,
  10. "TagA" /* Tag */,
  11. ("Hello RocketMQ ").getBytes("utf-8") /* Message body */
  12. );
  13. //Call send message to deliver message to one of brokers.
  14. SendResult sendResult = producer.send(msg);
  15. System.out.printf("%s%n", sendResult);
  16. //Shut down once the producer instance is not longer in use.
  17. producer.shutdown();
  18. }

经过跟踪发现标红部分的代码根本没有起作用,为什么没起作用呢,下面看下DefaultMQProducer的构造方法:

  1. public DefaultMQProducer(String producerGroup, RPCHook rpcHook) {
  2. this.log = ClientLogger.getLog();
  3. this.createTopicKey = "TBW102";
  4. this.defaultTopicQueueNums = 4;
  5. this.sendMsgTimeout = 3000;
  6. this.compressMsgBodyOverHowmuch = 4096;
  7. this.retryTimesWhenSendFailed = 2;
  8. this.retryTimesWhenSendAsyncFailed = 2;
  9. this.retryAnotherBrokerWhenNotStoreOK = false;
  10. this.maxMessageSize = 4194304;
  11. this.traceDispatcher = null;
  12. this.producerGroup = producerGroup;
  13. //创建DefaultMQProducerImpl对象
  14. this.defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
  15. }
  16. //发送消息
  17. public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
  18. return this.defaultMQProducerImpl.send(msg);
  19. }

从send方法以及DefaultMQProducer的构造方法可以看出,引入rocketmq-spring-boot-starter引入后导致MQClientInstance实例被提前创建,提前创建使用的是application.yml文件中配置:

  1. rocketmq:
  2. name-server: 127.0.0.1:9876
  3. producer:
  4. group: my-group

该配置里面使用的就是127.0.0.1 而不是docker中部署的nameserver地址,虽然使用producer.setNamesrvAddr(“172.21.52.27:9876”)设置了rocketmq nameserver地址,但是其实是无效的,具体原因可以在MQClientManager类getAndCreateMQClientInstance方法查看,

  1. public MQClientInstance getAndCreateMQClientInstance(ClientConfig clientConfig, RPCHook rpcHook) {
  2. String clientId = clientConfig.buildMQClientId();
  3. MQClientInstance instance = (MQClientInstance)this.factoryTable.get(clientId);
  4. if (null == instance) {
  5. instance = new MQClientInstance(clientConfig.cloneClientConfig(), this.factoryIndexGenerator.getAndIncrement(), clientId, rpcHook);
  6. MQClientInstance prev = (MQClientInstance)this.factoryTable.putIfAbsent(clientId, instance);
  7. if (prev != null) {
  8. instance = prev;
  9. log.warn("Returned Previous MQClientInstance for clientId:[{}]", clientId);
  10. } else {
  11. log.info("Created new MQClientInstance for clientId:[{}]", clientId);
  12. }
  13. }
  14. return instance;
  15. }

由于引入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发送信息

发表评论

表情:
评论列表 (有 0 条评论,47人围观)

还没有评论,来说两句吧...

相关阅读