本文介绍的主要内容是:启动broker的一些错误日志的处理,以及由于namesrvAddr为null,broker不能正确注册到name server的排查过程。结论是应该配置name server的地址值(环境变量)。
问题背景:

  1. 从github下载RocketMQ源码
  2. 根据对RocketMQ原理的理解,结合该篇文章:搭建RocketMQ源码环境 ,在idea中配置好本地运行环境,先启动name server模块,再启动broker模块,因为broker要将一些信息注册到name server上(name server角色相当于微服务中的eureka消息注册中心)。
  3. 我遇到的一些问题:
    (1) 我是windows环境,在windows下,环境变量user.home对应的是Desktop的上一层路径,所以我的环境,user.home是“C:\Users\Administrator”。
    在这里插入图片描述
    (2) 找到日志文件打印在哪里,下面是broker的配置文件
    在这里插入图片描述
    所以在windows上日志文件路径是:
    在这里插入图片描述
    (3) 先启动nameserver,启动类是:src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java,再启动broker,启动类是:src/main/java/org/apache/rocketmq/broker/BrokerStartup.java。这里正常操作应该查看两个模块的日志,因为控制台并不打印日志,我的一个错误:在控制台发现没报错,就去启动了example下的producer和consumer,准备测试消息的生产和消费。但producer启动报错了。
    在这里插入图片描述
    于是才想着去看日志…在broker.log发现了error
    在这里插入图片描述
    思考为什么会找不到这个路径下的文件,还是因为user.home在windows下的路径是Desktop的上一层,这里解决办法可以是修改源码,将这些文件的位置自定义,因为源码是:
    在这里插入图片描述
    或者直接在该默认路径下手动建立不存在的文件。所以broker启动日志不再报文件不存在这个类型的error。虽然nameserver和broker启动都不报错了,但是producer仍报上述错误。

(4) 再启动producer仍报上述错误,直接Debug broker的启动流程,下面是排除出问题的部分相关源码与解释:

public class BrokerStartup {

    public static void main(String[] args) {
    //需要createBrokerController返回一个brokerController,再调用start()启动
        start(createBrokerController(args));
    }
    public static BrokerController start(BrokerController controller) {
        try {

            controller.start();

            String tip = "The broker[" + controller.getBrokerConfig().getBrokerName() + ", "
                + controller.getBrokerAddr() + "] boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
//在做判断的地方打断点,如果正常,broker应该注册到nameserver,
//所以broker.log里应该打印出日志:应该包含and name server is,
//但是日志里并没有打印出这句日志,就说明这个判断条件失败了!!!
//controller.getBrokerConfig().getNamesrvAddr()是null。见后面调试截图。
            if (null != controller.getBrokerConfig().getNamesrvAddr()) {
                tip += " and name server is " + controller.getBrokerConfig().getNamesrvAddr();
            }

            log.info(tip);
            System.out.printf("%s%n", tip);
            return controller;
        } catch (Throwable e) {
            e.printStackTrace();
            System.exit(-1);
        }

        return null;
    }

    public static BrokerController createBrokerController(String[] args) {
        //省略部分源码...
        
            //这里打断点,因为namesrvAddr是从brokerConfig中get的
            final BrokerConfig brokerConfig = new BrokerConfig();
            final NettyServerConfig nettyServerConfig = new NettyServerConfig();
            final NettyClientConfig nettyClientConfig = new NettyClientConfig();
			//省略部分源码...
            if (BrokerRole.SLAVE == messageStoreConfig.getBrokerRole()) {
                int ratio = messageStoreConfig.getAccessMessageInMemoryMaxRatio() - 10;
                messageStoreConfig.setAccessMessageInMemoryMaxRatio(ratio);
            }
			//省略部分源码...
			//这里拿到namesrvAddr,发现是null
            String namesrvAddr = brokerConfig.getNamesrvAddr();
            if (null != namesrvAddr) {
                try {
                    String[] addrArray = namesrvAddr.split(";");
                    for (String addr : addrArray) {
                        RemotingUtil.string2SocketAddress(addr);
                    }
                } catch (Exception e) {
                    System.out.printf(
                        "The Name Server Address[%s] illegal, please set it as follows, \"127.0.0.1:9876;192.168.0.1:9876\"%n",
                        namesrvAddr);
                    System.exit(-3);
                }
            }     
            //省略部分源码...
}

debug发现new的brokerConfig实例中namesrvAddr=null,所以导致在start()方法中,if条件拿到的namesrvAddr是null,所以导致日志没有打印出带有“and name server is”信息的日志。

if (null != controller.getBrokerConfig().getNamesrvAddr()) {
                tip += " and name server is " + controller.getBrokerConfig().getNamesrvAddr();
            }

在这里插入图片描述
进一步查看BrokerConfig类,调用默认的构造,其中的属性有很多的默认值:
在这里插入图片描述
说明属性namesrvAddr就是在这里没有赋值成功,才返回null。正常情况下应该通过系统jvm参数获得namesrvAddr的值,如果获取不到,则通过环境变量NAMESRV_ADDR获得。而这里没有成功获取是因为没有配置name server地址
在这里插入图片描述
解决办法如下:

  • 由于在本机运行,所以namesrvAddr的值应该是127.0.0.1:9876,而这里直接private String namesrvAddr = "127.0.0.1:9876";【不推荐,在代码里写死了,应 配置>编码】
    在这里插入图片描述

  • 设置环境变量NAMESRV_ADDR的值,就像当初需要设置ROCKET_HOME环境变量一样。
    在这里插入图片描述
    我采用的是配置ROCKET_HOME环境变量的方式。可以成功获得namesrvAddr的值。
    在这里插入图片描述

  • JVM参数:- rocketmq.namesrv.addr=127.0.0.1:9876

  • 编码层面:setNamesrvAddr

再启动broker,可以打印日志:
在这里插入图片描述
表示broker成功拿到nameserver的地址并成功注册到nameserver。
再开启producer不再报错,可以正常生产和消费消息啦~
在这里插入图片描述
在这里插入图片描述
其实,在github源码的wiki里有这样一段话:
在这里插入图片描述

加油!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐