RocketMQ 报错 No topic route info in name server for the topic

本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net

目录

背景

问题排查

问题发现

问题分析

问题解决

解决方案

建议

总结


背景

业务团队使用的RocketMQ集群是我们中间件组搭建的,使用的客户端是微服务组基于原生的RocketMQ客户端封装的xcloud-rocketmq

业务团队在项目上线之后,反馈线上程序一直报错:

问题排查

1、看到业务团队这个表述,让我理解为线上集群存在问题,业务方topic在console创建成功了,但是发送消息时失败了,为了确保线上集群没问题,我先创建了一个测试的topic,写一个Java客户端进行发送消息,发现一切正常;

2、怀疑是客户端的问题,因为我使用的是原生的生产者,业务方使用的是微服务组封装的xcloud客户端,于是我使用了和业务方相同的客户端,测试结果仍然为正常,也没有报任何警告日志。

所以,用排除归纳法,能确定RocketMQ服务端和客户端都是正常的,不一样的是和业务方的使用方式、配置等。

问题发现

经过交流,发现业务方配置了RocketMQ客户端的日志,将RocketMQ客户端的日志也输出到了业务日志中,导致ELK采集到的业务日志一直打印RocketMQ客户端的异常信息,也就是说这个一直重复打印的日志,是一个警告日志,是RocketMQ客户端原生的日志。



1.  <logger >
2.    <appender-ref ref="INFO_FILE" />
3.  </logger>


查看了源码,发现RocketMQ客户端确实会默默将日志打印到一个目录:

我查看了一下本机的~/logs/rocketmqlogs目录,确实有日志文件

看到了完整的异常日志信息之后,发现一个重要的信息:No topic route info in name server for the topic:RMQ_SYS_TRACE_TOPIC

RMQ_SYS_TRACE_TOPIC:这个topic是broker开启消息跟踪之后,系统自动创建的,但是我没有开启呀,按理说是不应该有这个topic的异常信息的;

TBW102:这个topic是Broker启动时,当autoCreateTopicEnable的配置为true时,会自动创建该默认topic,当生产者发送消息的topic没有创建时,会先路由到这个默认的topic,然后再继承该topic的配置,创建新的topic,但是我也没有开启自动创建topic;

所以,按照日志的分析来看,问题总结如下:

客户端会定时更新topic的路由信息,以保证客户端生产消费的正确性,此时服务端发现客户端请求了一个未知的topic:RMQ_SYS_TRACE_TOPIC,这个topic通过console上查找确认了,查无此topic,按照RocketMQ路由不到topic的逻辑,此时TBW102就出现了,由于没有开启自动创建topic,TBW102也不存在,这就导致了这个死循环,那么问题来了:为什么服务端没有RMQ_SYS_TRACE_TOPIC这个topic,但是客户端会报这个异常?

问题分析

带着疑问,来看追踪报错信息的源头,发现客户端更新topic列表的时候,不是直接从服务端获取topic列表信息,而是先查询所有的Consumer和Producer集合,再通过Consumer和Producer来获取所关联的topic,代码如下:

为什么会这么做,不像Kafka一样直接获取topic列表呢?猜想是Kafka用zk来存储元数据信息,能保证数据的强一致性,而RocketMQ无法保证,只能以客户端自己缓存的Consumer和Producer作为依据,来查所路由的topic信息。

为什么服务端没有RMQ_SYS_TRACE_TOPIC这个topic,但是客户端会报这个异常?

猜测:

1、有系统或用户的Consumer或Producer,关联到了RMQ_SYS_TRACE_TOPIC这个topic;

2、用户开启了消息追踪,设置了消息追踪的参数为true,从而导致客户端获取到的topic列表包含了这个topic,而服务端没有,就一直循环报错。

问题解决

解决方案

首先看官方的issues,也有人提出这个问题:

https://github.com/apache/rocketmq/issues/2938

官方的解释是:RocketMQ在4.4.0之后,支持消息追踪,如果客户端设置了消息追踪为true,需要在broker的配置文件中设置tracetopicEnable=true

这也符合我的猜想,应该是有客户端在构造Producer时,将tracetopicEnable参数传了true,所以需要传false或不传,或者将服务端配置修改为支持消息追踪。

`

1.  public class Producer {
2.      public static void main(String[] args) throws MQClientException, InterruptedException {
3.  ​
4.          DefaultMQProducer producer = new DefaultMQProducer("zhurunhua", false);
5.          producer.setNamesrvAddr("172.20.10.42:9976;172.20.10.43:9976");
6.          producer.start();
7.          long l = System.currentTimeMillis();
8.          try {
9.              Message msg = new Message("test_topic",
10.                      "TagA",
11.                      "OrderID188",
12.                      "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
13.              SendResult sendResult = producer.send(msg);
14.              System.out.printf("cost:%s-->%s%n", (System.currentTimeMillis() - l), sendResult);
15.          } catch (Exception e) {
16.              log.error("", e);
17.          }
18.          producer.shutdown();
19.      }
20.  }

`![][img-6]

但是查看的业务方的代码,并没有将消息追踪设置为true

`

1.  @Component
2.  @Slf4j
3.  public class MqComp {
4.      @Resource
5.      private RocketMQTemplate rocketMqTemplate;
6.  ​
7.      public SendResult syncSendOrderly(String destination, Message<?> message, String hashKey) {
8.          return rocketMqTemplate.syncSendOrderly(destination, message, hashKey);
9.      }
10.  ​
11.      public void send(String destination, Message<?> message) {
12.          rocketMqTemplate.send(destination, message);
13.      }
14.  ​
15.      public void asyncSend(String destination, Message<?> message, SendCallback sendCallback, long timeout) {
16.          rocketMqTemplate.asyncSend(destination, message, sendCallback, timeout);
17.      }
18.  }

`![][img-7]

于是我猜测,微服务组封装的客户端,默认将消息追踪打开了,果不其然:

所以需要联系微服务组将该参数改为可配置的,或者修改broker配置,将traceTopicEnable设置为true。

建议

由于RocketMQ客户端本身的日志也很庞大,每隔几秒就会刷新路由信息,可以将RocketMQ客户端的日志级别调低,来看源码是如何制定的:

所有可以在配置文件中指定日志级别和路径:



1.  rocketmq:
2.    client:
3.      logRoot: ./logs/rmq
4.      logLevel: ERROR
5.      logFileName: rocketmq-client.log


总结

  • 出现该问题的根本原因在于:服务端不支持消息追踪的情况下,客户端设置enableMsgTrace=true

  • 由于服务端和客户端分属两个团队负责,并且业务方阐述问题并不是很明确,所以问题排查过程有些困难,需要熟悉客户端的配置及使用,便于以后更快定位问题

posted @ 2022-08-16 11:17  托马斯布莱克  阅读(4913)  评论(0编辑  收藏  举报