NameServer是一个注册中心,Broker在启动时向所有的NameServer注册,生产者Producer和消费者Consumer可以从NameServer中获取所有注册的Broker列表,并从中选取Broker进行消息的发送和消费。

NameServer的启动类是NamesrvStartup,主要做了两件事情:

  1. 调用createNamesrvController方法创建NamesrvControllerNamesrvController是NameServer的核心
  2. 调用start方法,启动NameServer
  1. public class NamesrvStartup {
  2. private static InternalLogger log;
  3. private static Properties properties = null;
  4. private static CommandLine commandLine = null;
  5. public static void main(String[] args) {
  6. // 启动入口
  7. main0(args);
  8. }
  9. public static NamesrvController main0(String[] args) {
  10. try {
  11. // 创建NamesrvController
  12. NamesrvController controller = createNamesrvController(args);
  13. // 启动nameserver
  14. start(controller);
  15. String tip = "The Name Server boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
  16. log.info(tip);
  17. System.out.printf("%s%n", tip);
  18. return controller;
  19. } catch (Throwable e) {
  20. e.printStackTrace();
  21. System.exit(-1);
  22. }
  23. return null;
  24. }
  25. }

创建NamesrvController

createNamesrvController方法主要是对配置信息进行处理:

  1. 创建NamesrvConfig,从名字可以看出是记录NameServer的相关配置信息
  2. 创建NettyServerConfig,与Netty服务相关的配置信息,默认设置监听端口为9876
  3. 从启动命令中检查是否通过- c指定了配置文件,如果指定了配置文件,从指定的路径中加载文件,并将解析文件将配置保存到NamesrvConfigNettyServerConfig
  4. 校验RocketMQ的主目录是否为空,可以在启动命令中通过-Drocketmq.home.dir=路径指定主目录,也可以在操作系统设置环境变量ROCKETMQ_HOME的方式来指定
  5. 处理日志相关的设置
  6. 创建NamesrvController并返回
  1. public class NamesrvStartup {
  2. public static NamesrvController createNamesrvController(String[] args) throws IOException, JoranException {
  3. System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
  4. Options options = ServerUtil.buildCommandlineOptions(new Options());
  5. commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser());
  6. if (null == commandLine) {
  7. System.exit(-1);
  8. return null;
  9. }
  10. // Nameserver相关配置
  11. final NamesrvConfig namesrvConfig = new NamesrvConfig();
  12. // Netty服务器连接相关配置
  13. final NettyServerConfig nettyServerConfig = new NettyServerConfig();
  14. // 设置端口
  15. nettyServerConfig.setListenPort(9876);
  16. // 如果启动命令中指定了配置文件
  17. if (commandLine.hasOption('c')) {
  18. String file = commandLine.getOptionValue('c');
  19. if (file != null) {
  20. // 获取文件
  21. InputStream in = new BufferedInputStream(new FileInputStream(file));
  22. properties = new Properties();
  23. properties.load(in);
  24. // 解析配置文件
  25. MixAll.properties2Object(properties, namesrvConfig);
  26. MixAll.properties2Object(properties, nettyServerConfig);
  27. namesrvConfig.setConfigStorePath(file);
  28. System.out.printf("load config properties file OK, %s%n", file);
  29. in.close();
  30. }
  31. }
  32. // 如果启动命令中带了-p参数,打印NameServer的相关配置信息
  33. if (commandLine.hasOption('p')) {
  34. InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
  35. MixAll.printObjectProperties(console, namesrvConfig);
  36. MixAll.printObjectProperties(console, nettyServerConfig);
  37. System.exit(0);
  38. }
  39. // 将启动命令中的一些设置记录到namesrvConfig
  40. MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
  41. // 如果RocketMQ主目录获取为空,打印异常信息
  42. if (null == namesrvConfig.getRocketmqHome()) {
  43. System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation%n", MixAll.ROCKETMQ_HOME_ENV);
  44. System.exit(-2);
  45. }
  46. // 日志相关设置
  47. LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
  48. JoranConfigurator configurator = new JoranConfigurator();
  49. configurator.setContext(lc);
  50. lc.reset();
  51. configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");
  52. log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
  53. MixAll.printObjectProperties(log, namesrvConfig);
  54. MixAll.printObjectProperties(log, nettyServerConfig);
  55. // 创建NamesrvController
  56. final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);
  57. controller.getConfiguration().registerConfig(properties);
  58. return controller;
  59. }
  60. }

启动NameServer

NameServer的启动主要通过NamesrvController进行,处理逻辑如下:

  1. 调用NamesrvController的initialize函数进行初始化
  2. 注册JVM关闭钩子函数,在JVM关闭的时候,调用NamesrvController的shutdown方法关闭相关资源
  3. 调用NamesrvController的start方法启动NameServer
  1. public class NamesrvStartup {
  2. public static NamesrvController start(final NamesrvController controller) throws Exception {
  3. if (null == controller) {
  4. throw new IllegalArgumentException("NamesrvController is null");
  5. }
  6. // 初始化NamesrvController
  7. boolean initResult = controller.initialize();
  8. if (!initResult) {
  9. controller.shutdown();
  10. System.exit(-3);
  11. }
  12. // 注册JVM关闭钩子函数
  13. Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() {
  14. @Override
  15. public Void call() throws Exception {
  16. controller.shutdown();
  17. return null;
  18. }
  19. }));
  20. // 启动nameserver
  21. controller.start();
  22. return controller;
  23. }
  24. }

NamesrvController

初始化

NamesrvController的初始化方法中主要做了如下操作:

  1. 加载配置信息,主要是从kvConfig.json中加载数据
  2. 创建NettyRemotingServer,用于网络通信
  3. 根据设置的工作线程数量创建netty服务相关线程池
  4. 注册处理器DefaultRequestProcessor,用于处理收到的请求,比如Broker发起的注册请求
  5. 注册用于心跳检测的定时任务,定时扫描处于不活跃状态的Broker并剔除
  6. 注册定时打印KV信息的任务
  1. public class NamesrvController {
  2. private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
  3. private final NamesrvConfig namesrvConfig; // NameServer相关配置
  4. private final NettyServerConfig nettyServerConfig; // Netty服务相关配置
  5. private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
  6. "NSScheduledThread")); // 定时执行任务的线程池
  7. private final KVConfigManager kvConfigManager;
  8. private final RouteInfoManager routeInfoManager; // 路由表
  9. private RemotingServer remotingServer; // 远程服务,使用的是NettyRemotingServer
  10. private BrokerHousekeepingService brokerHousekeepingService;
  11. private ExecutorService remotingExecutor; // Netty服务相关线程池
  12. // ...
  13. public boolean initialize() {
  14. // 加载配置信息
  15. this.kvConfigManager.load();
  16. // 创建NettyRemotingServer
  17. this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
  18. // 创建netty服务相关线程池
  19. this.remotingExecutor =
  20. Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_"));
  21. // 注册处理器
  22. this.registerProcessor();
  23. // 定时任务,扫描Broker
  24. this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
  25. @Override
  26. public void run() {
  27. // 心跳监测扫描处于不活跃状态的Broker
  28. NamesrvController.this.routeInfoManager.scanNotActiveBroker();
  29. }
  30. }, 5, 10, TimeUnit.SECONDS);
  31. // 定时打印KV配置信息
  32. this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
  33. @Override
  34. public void run() {
  35. NamesrvController.this.kvConfigManager.printAllPeriodically();
  36. }
  37. }, 1, 10, TimeUnit.MINUTES);
  38. // ....
  39. return true;
  40. }
  41. // 注册处理器
  42. private void registerProcessor() {
  43. if (namesrvConfig.isClusterTest()) {
  44. this.remotingServer.registerDefaultProcessor(new ClusterTestRequestProcessor(this, namesrvConfig.getProductEnvName()),
  45. this.remotingExecutor);
  46. } else {
  47. // 注册DefaultRequestProcessor处理请求
  48. this.remotingServer.registerDefaultProcessor(new DefaultRequestProcessor(this), this.remotingExecutor);
  49. }
  50. }
  51. }

启动

在启动方法中,主要是调用了RemotingServer的start方法启动服务,在NamesrvController的初始化方法中可知,使用的实现类是NettyRemotingServer,所以之后会启动Netty服务:

  1. public void start() throws Exception {
  2. // 启动Netty服务
  3. this.remotingServer.start();
  4. if (this.fileWatchService != null) {
  5. this.fileWatchService.start();
  6. }
  7. }
Netty启动

NettyRemotingServer的start方法中主要是对Netty的一些设置,然后绑定端口并启动服务:

  1. public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
  2. @Override
  3. public void start() {
  4. // ...
  5. prepareSharableHandlers();
  6. // Netty相关设置
  7. ServerBootstrap childHandler =
  8. this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector) // 设置EventLoopGroup线程组
  9. .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) // 设置channel类型
  10. .option(ChannelOption.SO_BACKLOG, nettyServerConfig.getServerSocketBacklog())
  11. .option(ChannelOption.SO_REUSEADDR, true)
  12. .option(ChannelOption.SO_KEEPALIVE, false)
  13. .childOption(ChannelOption.TCP_NODELAY, true)
  14. .localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort())) // 设置端口
  15. .childHandler(new ChannelInitializer<SocketChannel>() {
  16. @Override
  17. public void initChannel(SocketChannel ch) throws Exception { // 设置ChannelHandler
  18. ch.pipeline()
  19. .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, handshakeHandler)
  20. .addLast(defaultEventExecutorGroup,
  21. encoder,
  22. new NettyDecoder(),
  23. new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
  24. connectionManageHandler,
  25. serverHandler
  26. );
  27. }
  28. });
  29. if (nettyServerConfig.getServerSocketSndBufSize() > 0) {
  30. log.info("server set SO_SNDBUF to {}", nettyServerConfig.getServerSocketSndBufSize());
  31. // 设置Socket发送缓存区大小
  32. childHandler.childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize());
  33. }
  34. if (nettyServerConfig.getServerSocketRcvBufSize() > 0) {
  35. log.info("server set SO_RCVBUF to {}", nettyServerConfig.getServerSocketRcvBufSize());
  36. // 设置Socket接收缓存区大小
  37. childHandler.childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize());
  38. }
  39. if (nettyServerConfig.getWriteBufferLowWaterMark() > 0 && nettyServerConfig.getWriteBufferHighWaterMark() > 0) {
  40. log.info("server set netty WRITE_BUFFER_WATER_MARK to {},{}",
  41. nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark());
  42. childHandler.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(
  43. nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark()));
  44. }
  45. if (nettyServerConfig.isServerPooledByteBufAllocatorEnable()) {
  46. childHandler.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
  47. }
  48. try {
  49. // 绑定端口并启动服务
  50. ChannelFuture sync = this.serverBootstrap.bind().sync();
  51. InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress();
  52. this.port = addr.getPort();
  53. } catch (InterruptedException e1) {
  54. throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1);
  55. }
  56. if (this.channelEventListener != null) {
  57. this.nettyEventExecutor.start();
  58. }
  59. this.timer.scheduleAtFixedRate(new TimerTask() {
  60. @Override
  61. public void run() {
  62. try {
  63. NettyRemotingServer.this.scanResponseTable();
  64. } catch (Throwable e) {
  65. log.error("scanResponseTable exception", e);
  66. }
  67. }
  68. }, 1000 * 3, 1000);
  69. }
  70. }

参考

丁威、周继锋《RocketMQ技术内幕》

RocketMQ版本:4.9.3

【RocketMQ】NameServer的启动的更多相关文章

  1. RocketMQ中NameServer的启动

    在RocketMQ中,使用NamesrvStartup作为启动类 主函数作为其启动的入口: public static void main(String[] args) { main0(args); ...

  2. RocketMQ之消费者启动与消费流程

    vivo 互联网服务器团队 - Li Kui 一.简介 1.1 RocketMQ 简介 RocketMQ是由阿里巴巴开源的分布式消息中间件,支持顺序消息.定时消息.自定义过滤器.负载均衡.pull/p ...

  3. 关于rocketmq的配置启动

    #集群名称brokerClusterName=rocket-nameserver#broker-a,注意其它两个分别为broker-b和broker-cbrokerName=broker-a#brok ...

  4. 一张图进阶 RocketMQ - NameServer

    前言 「三此君看了好几本书,看了很多遍源码整理的 一张图进阶 RocketMQ 图片链接,关于 RocketMQ 你只需要记住这张图!觉得不错的话,记得点赞关注哦.」 一张图进阶 RocketMQ 图 ...

  5. RocketMQ的broker启动失败解决

    RocketMQ的broker用如下命令启动: nohup sh bin/mqbroker -n localhost:9876 & 使用jps查看,系统非常卡顿,broker的名字也未显示.使 ...

  6. RocketMQ NameServer

    NameServer  路由管理,服务注册,服务发现.(类比为soa框架中的zookeeper) 一.路由管理 1.路由注册,由 Broker 向 NameServer 发送心跳,NameServer ...

  7. 修改RocketMQ的NameServer端口

    ---问题--- 有同事提出各个问题:如何修改RocketMQ的NameServer端口号?(默认:9876) ---结论--- 调查并验证之后,结论及过程如下: 验证版本:rocketmq-all- ...

  8. RocketMQ中Broker的启动源码分析(一)

    在RocketMQ中,使用BrokerStartup作为启动类,相较于NameServer的启动,Broker作为RocketMQ的核心可复杂得多 [RocketMQ中NameServer的启动源码分 ...

  9. rocketmq 部署启动指南-Docker 版

    最近学习使用 rocketmq,需要搭建 rocketmq 服务端,本文主要记录 rocketmq 搭建过程以及这个过程踩到的一些坑. 准备工作 在搭建之前,我们需要做一些准备工作,这里我们需要使用 ...

随机推荐

  1. Ubuntu中hyperledger-fabric2.3.0环境搭建

    系统环境 hyperledger-fabric在Ubuntu安装过程,fabric版本为2.3.0 首先安装相关软件 1.安装docker 直接参考下面这篇文档安装好docker-ce即可 Ubunt ...

  2. Mybatis注解开发(一对一)

    其他代码访问:Mybatis注解开发基础操作 1.添加OrderMapper接口 public interface OrderMapper { // @Select("select *,o. ...

  3. 导入,导出excel

    /// <summary> /// 导出数据 /// </summary> /// <param name="XMMC"></param& ...

  4. mosquitto使用与常用配置

    为了方便演示,我这里就用windows环境下安装的mosquitto进行操作,操作方式和linux系统下是一样的. 一.windows安装mosquitto 下载mosquitto mosquitto ...

  5. CentOS7.x 离线安装和开机启动 supervisor 4.2.4

    CentOS7.x 服务器 离线安装 开机启动 supervisor 4.2.4

  6. echarts饼图禁止鼠标悬浮区块突出

    禁止悬浮突出,在series内添加hoverAnimation:false即可 代码如下: option = { color:['#3498db','#EEEEEE'], series: [ { na ...

  7. Go xmas2020 学习笔记 12、Structs, Struct tags & JSON

    12-Structs, Struct tags & JSON. Struct. Struct Gotcha. Anonymous Struct Type. Make the zero valu ...

  8. springcloud集群测试

    使用ribbon实现负载均衡,访问同一个url,轮询不同的服务提供端,从不同的数据库中取数据.

  9. Java语言学习day12--7月11日

    ###16随机点名器代码实现 * A: 随机点名器案例代码 /* 随机点名器,集合改进 (学生的姓名和年龄) 现实中有学生这个事物,使用定义类的形式,描述学生事物 属性: 姓名,年龄 姓名存储了数组, ...

  10. 【LeetCode】49. 字母异位词分组

    49. 字母异位词分组 知识点:字符串:哈希表 题目描述 给你一个字符串数组,请你将 字母异位词 组合在一起.可以按任意顺序返回结果列表. 字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源 ...