RocketMq之nameserver源码阅读

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: RocketMq之nameserver源码阅读

下载、编译源码

1.下载源码

点击rocketmq源码,fork一份到自己的repository中

image.png

通过git工具下载到本地,不擅长命令行的小伙伴,可通过sourcetree等git可视化工具操作;

没有创建自己账号的小伙伴可以直接clone一份代码下来,如下图所示的第一、二步骤所示:

image.png

实在是不会用git的小伙伴,也可以直接下载项目压缩包,也就是上图所示的第三步。

2.导入项目到idea

image.png

通过idea导入,选择maven工程

image.png

下图是导入后的项目结构:

image.png

至此,项目下载并且导入的工作已经完成。

3.编译项目

找到Terminal。找不到的小伙伴可以点击上面的View,找到Tool Windows中的Terminal

image.png

在Terminal输入以下命令:

mvn -Prelease-all -DskipTests -Dcheckstyle.skip=true clean install -U
复制代码

编译完成后,项目中多出一个target文件夹,并且Terminal现实全部编译成功:

image.png

4.开始运行Nameserver启动代码

image.png

此时,idea会输出一系列错误,这些都属于代码编译错误。

image.png

因为我们已经通过maven编译好了代码,所以不需要在每次Run的时候通过idea自动编译,那么就需要修改一下配置

image.png

选择Run之前需要执行的操作,点击删除。意味着咱们在Run之前啥也不做,直接Run。

image.png

image.png

至此,咱们的基本配置全部完成,下一步可以开始通过Debug的方式阅读NameServer的源码了。

Debug调试阅读源码

image.png

找到main入口函数,发现直接调用了main0(String[] args)函数。

main0(String[] args)函数中第一步先创建NamesrvController

public static NamesrvController createNamesrvController(String[] args) throws IOException, JoranException {
        // 设置版本号
        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
        // 构建命令行选项-h,-c
        Options options = ServerUtil.buildCommandlineOptions(new Options());
        // 解析命令行选项,生成一个commandLine对象
        commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser());
        if (null == commandLine) {
            System.exit(-1);
            return null;
        }
        // 创建一个NamesrvConfig对象,里面的属性默认会查找rocketmq.home.dir参数或ROCKETMQ_HOME环境变量
        final NamesrvConfig namesrvConfig = new NamesrvConfig();
        // 其实重点就是获取这两个配置对象
        final NettyServerConfig nettyServerConfig = new NettyServerConfig();
        nettyServerConfig.setListenPort(9876);
        // 读取配置文件,并更新namesrvConfig
        if (commandLine.hasOption('c')) {
            String file = commandLine.getOptionValue('c');
            if (file != null) {
                InputStream in = new BufferedInputStream(new FileInputStream(file));
                properties = new Properties();
                properties.load(in);
                MixAll.properties2Object(properties, namesrvConfig);
                MixAll.properties2Object(properties, nettyServerConfig);
                namesrvConfig.setConfigStorePath(file);
                System.out.printf("load config properties file OK, %s%n", file);
                in.close();
            }
        }
        // 如果启动命令中有-p,那么就打印namesrvConfig和nettyServerConfig后结束程序
        if (commandLine.hasOption('p')) {
            InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
            MixAll.printObjectProperties(console, namesrvConfig);
            MixAll.printObjectProperties(console, nettyServerConfig);
            System.exit(0);
        }
        // 把读取到的配置文件全部设置到namesrvConfig中
        MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
        // 如果没有找搭配参数rocketmq.home.dir或者ROCKETMQ_HOME环境变量,那么就直接结束程序
        if (null == namesrvConfig.getRocketmqHome()) {
            System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation%n", MixAll.ROCKETMQ_HOME_ENV);
            System.exit(-2);
        }
        // 准备日志对象
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        configurator.setContext(lc);
        lc.reset();
        // 需要找到日志配置文件
        configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");
        log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
        // 打印两个配置对象
        MixAll.printObjectProperties(log, namesrvConfig);
        MixAll.printObjectProperties(log, nettyServerConfig);
        //这个才是真正的创建NamesrvController对象,前提是需要准备好namesrvConfig和nettyServerConfig
        final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);
        // 把所有的配置写回到nameserver的配置文件中
        // remember all configs to prevent discard
        controller.getConfiguration().registerConfig(properties);
        return controller;
    }
复制代码

在上述源码可以看出,如果没有在启动参数中设置rocketmq.home.dir,或者没有配置ROCKETMQ_HOME环境变量,那么程序就会直接启动失败。

// 如果没有找搭配参数rocketmq.home.dir或者ROCKETMQ_HOME环境变量,那么就直接结束程序
        if (null == namesrvConfig.getRocketmqHome()) {
            System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation%n", MixAll.ROCKETMQ_HOME_ENV);
            System.exit(-2);
        }
复制代码

image.png

基于上述源码的阅读,我们想要启动成功,需要在启动参数中设置rocketmq.home.dir

-Drocketmq.home.dir=当前项目所在的路径
复制代码

image.png

再次启动main函数。结果报错说找不到日志配置文件

image.png

// 需要找到日志配置文件
        configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");
复制代码

源码中会在rocketmqHome后面拼接一个/conf/logback_namesrv.xml路径,那么我们就需要根据代码中的要求去创建一个conf文件,并且在里面创建一个logback_namesrv.xml日志配置文件

image.png

通过翻阅项目模块,我们发现在distribution模块中,已经有一个logback_namesrv.xml日志配置文件了,那么我们直接把它拷贝到新创建的conf文件夹中。

再次运行main入口函数,我们就可以启动成功了。

image.png

以上createNamesrvController(String[] args)函数做的事情,可以总结为两点:

1.根本目的就是为了创建NamesrvController对象

2.创建一个NamesrvController对象需要先创建NamesrvConfig和NettyServerConfig对象

所以这个函数里面大部分都是在处理配置参数。创建好NamesrvController后,就开始启动它了。

public static NamesrvController main0(String[] args) {
        try {
            //创建NamesrvController
            NamesrvController controller = createNamesrvController(args);
            //启动NamesrvController
            start(controller);
            String tip = "The Name Server boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
            log.info(tip);
            System.out.printf("%s%n", tip);
            return controller;
        } catch (Throwable e) {
            e.printStackTrace();
            System.exit(-1);
        }
        return null;
    }



相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
3月前
|
消息中间件 存储 监控
深度写作:深入源码理解MQ长轮询优化机制
【11月更文挑战第22天】在分布式系统中,消息队列(Message Queue, MQ)扮演着至关重要的角色。MQ不仅实现了应用间的解耦,还提供了异步消息处理、流量削峰等功能。而在MQ的众多特性中,长轮询(Long Polling)机制因其能有效提升消息处理的实时性和效率,备受关注。
111 12
|
3月前
|
消息中间件 存储 Java
深入源码理解MQ长轮询优化机制
【11月更文挑战第22天】在分布式系统中,消息队列(MQ)作为一种重要的中间件,广泛应用于解耦、异步处理、流量削峰等场景。其中,延时消息和定时消息作为MQ的高级功能,能够进一步满足复杂的业务需求。为了实现这些功能,MQ系统需要进行一系列优化,长轮询机制便是其中的关键一环。本文将深入探讨MQ如何设计延时消息和定时消息的优化机制,特别是长轮询机制的实现原理及其在Java中的模拟实现。
67 2
|
8月前
|
消息中间件 数据可视化 Go
Rabbitmq 搭建使用案例 [附源码]
Rabbitmq 搭建使用案例 [附源码]
65 0
|
4月前
|
消息中间件 存储 SQL
代码很少,却很优秀!RocketMQ的NameServer做到了!
本文深入剖析了RocketMQ的注册中心NameServer,基于RocketMQ release-5.2.0版本。NameServer作为Broker、Producer与Consumer之间的纽带,仅由少数几个类构成,却实现了高性能与轻量化。文章详细介绍了NameServer的AP设计思想、简洁的数据结构及心跳机制。AP设计避免了复杂的分布式协议,简化了网络开销;数据结构主要包括路由表、Broker信息等;心跳机制则通过定时扫描确保Broker的活跃状态。通过这些核心设计,NameServer实现了高效稳定的注册与发现功能。
216 5
|
4月前
|
传感器 数据可视化 网络协议
DIY可视化整合MQTT生成UniApp源码
DIY可视化整合MQTT生成UniApp源码
83 0
|
7月前
|
消息中间件 安全 fastjson
消息队列 MQ使用问题之NameServer集群是什么结构
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
7月前
|
消息中间件 数据安全/隐私保护 RocketMQ
消息队列 MQ使用问题之如何设置nameserver监听的IP
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
9月前
|
消息中间件 存储 Java
RocketMQ实战教程之NameServer与BrokerServer
这是一个关于RocketMQ实战教程的概要,主要讨论NameServer和BrokerServer的角色。NameServer负责管理所有BrokerServer,而BrokerServer存储和传输消息。生产者和消费者通过NameServer找到合适的Broker进行交互,不需要直接知道Broker的具体信息。工作流程包括生产者向NameServer查询后发送消息到Broker,以及消费者同样通过NameServer获取消息进行消费。这种设计类似于服务注册中心的概念,便于系统扩展和集群管理。
|
9月前
|
消息中间件 小程序 网络性能优化
蓝易云 - 直播小程序源码有用的协议知识:MQTT协
在直播小程序源码中,MQTT协议可以用于实现实时消息推送,如弹幕、聊天消息、礼物信息等。通过使用MQTT协议,可以确保消息的实时性和可靠性,从而提高用户体验。
209 0
|
9月前
|
消息中间件 Java 调度
【深度挖掘RocketMQ底层源码】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行调度的流程(Pull模式)
【深度挖掘RocketMQ底层源码】「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行调度的流程(Pull模式)
98 1