How RocketMQ.2-NameServer started

The previous article described the process of starting NameServer and broker with RocketMQ source code for single-machine deployment and sending and receiving messages. In fact, it is a simple quickstart. After the actual operation, the backend monarch has been able to carry out simple business messaging based on RocketMQ, completing small functions such as asynchronous consumption collection logs.

There are many examples of different types of messages on RocketMQ's official website. It is recommended that students who want to learn RocketMQ write these Demo s by hand first, and then go to the source code after they know the characteristics of message types such as sequential, broadcast, timed, batch, etc.

Next is the next day's body of RocketMQ. Today we'll talk about NameServer's startup process and source code analysis of its main functions.

Overview of NameServer

NameServer is a server that provides lightweight service discovery and routing. It has two main functions:

  • Agent management, NameServer accepts registration from the Broker cluster, and provides a heartbeat mechanism to check whether the Broker is active.
  • Routing management, where each name server holds the entire routing information about the Broker cluster and queue information for client queries.

We can think of NameServer as a lightweight registry.In fact, RocketMQ used Zookeeper as its registry in the past, and later removed Zookeeper dependency and replaced it with NameServer because RocketMQ's own architecture did not require an election mechanism like Zookeeper to select master nodes.

As the Registration Center for RocketMQ, NameServer receives the registration of all brokers in the cluster and provides a heartbeat mechanism every 10 seconds to check whether the Broker is up to date. If the Broker is not updated for more than 120 seconds, it is considered invalid and removed from the cluster.

After learning about NameServer's capabilities, the back-end can't help thinking, how do these functions work for NameServer?This requires looking through the source code.

Nameserver Startup Process Analysis

As mentioned in the previous Quick Start article, starting NameServer requires finding the NamesrcStartup class in the namesrv package, and studying the NameServer startup process starts with the main method of this class.

Resolve Configuration

The first step in starting NameServer is to construct a NamesrvController instance, which is the core class of NameServer.

public static NamesrvController main0(String[] args) {
    try {
        // Construct NamesrvController class
        NamesrvController controller = createNamesrvController(args);
        // Initialize, start NamesrvController class
        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;
}

The createNamesrvController method, on the other hand, receives parameters from the command line and parses them into the configuration classes NamesrvConfig and NettyServerConfig.

final NamesrvConfig namesrvConfig = new NamesrvConfig();
final NettyServerConfig nettyServerConfig = new NettyServerConfig();
// RocketMQ default port is 9876
nettyServerConfig.setListenPort(9876);
// Specify the configuration file with the -c parameter
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();
    }
}
// Print the current configuration with the -p parameter and exit the program
if (commandLine.hasOption('p')) {
    InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
    MixAll.printObjectProperties(console, namesrvConfig);
    MixAll.printObjectProperties(console, nettyServerConfig);
    System.exit(0);
}
// Specify property value by "--specific property name property value"
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);

We know that running RocketMQ from the command line can specify parameters, and it works just as the code above shows.

The -c command allows you to specify a configuration file that parses the contents of the configuration file intoJava.util.PropertiesClass, then assign to NamesrvConfig and NettyServerConfig classes to complete the parsing and mapping of the configuration file.

If the -p command is specified, the configuration information is printed in the console and the program exits directly.

In addition, you can use the -n parameter to specify the value of namesrvAddr, which isOrg.apache.rocketmq.Srvutil.ServerUtil#buildCommandlineOptionsThe parameters specified in the method are beyond the scope of this section. Interested students can look over the source code for debugging.

When the mapping of configuration properties is completed, a NamesrvController instance is constructed based on the configuration classes NamesrvConfig and NettyServerConfig.

final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);

Initialization and heartbeat mechanism

The second step in starting NameServer is to complete the initialization through NamesrvController#initialize.

public boolean initialize() {
    // Load`kvConfig.json`KV`configurations in the configuration file and place them in the `KVConfigManager#configTable` property
    this.kvConfigManager.load();
    // Start a `Netty'server based on `NettyServerConfig`
    this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
    // Initialize the thread pool responsible for processing `Netty`network interaction data
    this.remotingExecutor = Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_"));
    this.registerProcessor();
    
    // Register Heartbeat Mechanism Thread Pool
    this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            NamesrvController.this.routeInfoManager.scanNotActiveBroker();
        }
    }, 5, 10, TimeUnit.SECONDS);
    
    // Register Print KV Configuration Thread Pool
    this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            NamesrvController.this.kvConfigManager.printAllPeriodically();
        }
    }, 1, 10, TimeUnit.MINUTES);

   // Omit the following code...

    return true;
}

During the initialization of the NamesrvController, a thread pool of heartbeat mechanisms is registered, which starts scanning inactive broker s every 10 seconds five seconds after startup.

public void scanNotActiveBroker() {
    Iterator<Entry<String, BrokerLiveInfo>> it = this.brokerLiveTable.entrySet().iterator();
    while (it.hasNext()) {
        Entry<String, BrokerLiveInfo> next = it.next();
        long last = next.getValue().getLastUpdateTimestamp();
        // BROKER_CHANNEL_EXPIRED_TIME = 1000 * 60 * 2; that is, 120 seconds
        if ((last + BROKER_CHANNEL_EXPIRED_TIME) < System.currentTimeMillis()) {
            RemotingUtil.closeChannel(next.getValue().getChannel());
            // Remove the broker from the brokerLiveTable
            it.remove();
            log.warn("The broker channel expired, {} {}ms", next.getKey(), BROKER_CHANNEL_EXPIRED_TIME);
            this.onChannelDestroy(next.getKey(), next.getValue().getChannel());
        }
    }
}

You can see that in the scanNotActiveBroker method, NameServer traverses the property RouteInfoManager#brokerLiveTable.

private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;

class BrokerLiveInfo {
    // Active timestamp of broker last update
    private long lastUpdateTimestamp;
    private DataVersion dataVersion;
    private Channel channel;
    private String haServerAddr;
}

The RouteInfoManager#brokerLiveTable property stores the active information for all brokers in the cluster, mainly the BrokerLiveInfo#lastUpdateTimestamp property, which describes the active timestamp of the broker's last update.If the lastUpdateTimestamp property is not updated for more than 120 seconds, the broker is considered invalid and removed from the brokerLiveTable.

In addition to the thread pool of the heartbeat mechanism, another thread pool is registered, which prints all KV configuration information every 10 seconds.

Elegant downtime

The final step in NameServer's startup is to register a hook function for the JVM that will execute before the JVM closes.The hook function is used to free up resources, such as closing the Netty server, closing the thread pool, and so on.

Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() {
    @Override
    public Void call() throws Exception {
        controller.shutdown();
        return null;
    }
}));

Summary

This paper describes the role of NameServer, and based on its startup class NamesrvStartup, the startup process, as well as the heart beat mechanism and the principle of elegant downtime are analyzed.

Hope you can help.

Reference

Copyright notice: This is Planeswalker23 Created, reprinted please bring the original link, thank you.
This article has uploaded a personal public number, welcome to sweep code.

.

Tags: Java Zookeeper Netty jvm Apache

Posted on Fri, 12 Jun 2020 22:26:33 -0400 by maverickminds