public class NamesrvStartup { public static Properties properties = null; public static CommandLine commandLine = null; public static void main(String[] args) { main0(args); } public static NamesrvController main0(String[] args) { System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION)); try { //PackageConflictDetect.detectFastjson(); Options options = ServerUtil.buildCommandlineOptions(new Options());------------args是用java -jar 后面输入的字符串,按照键值对输入的,这一步是解析命令行的参数,c是指定config的配置文件,p看样子是退出? commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser()); if (null == commandLine) { System.exit(-1); return null; } final NamesrvConfig namesrvConfig = new NamesrvConfig(); final NettyServerConfig nettyServerConfig = new NettyServerConfig(); nettyServerConfig.setListenPort(9876); 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, " + file + "%n"); in.close(); } } if (commandLine.hasOption('p')) { MixAll.printObjectProperties(null, namesrvConfig); MixAll.printObjectProperties(null, nettyServerConfig); System.exit(0); } MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig); 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"); final Logger log = LoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); MixAll.printObjectProperties(log, namesrvConfig); MixAll.printObjectProperties(log, nettyServerConfig); ----------------这个controller是关键类,传入两个配置文件进去 final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig); // remember all configs to prevent discard controller.getConfiguration().registerConfig(properties); --------------看下面的start方法,实际是调用controller中的一个叫remotingServer的参数的start方法,而remotingServer的赋值就是在这个initialize方法中,new一个NettyRemotingServer出来,是调用netty的入口(见下文) boolean initResult = controller.initialize(); if (!initResult) { controller.shutdown(); System.exit(-3); } Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() { @Override public Void call() throws Exception { controller.shutdown(); return null; } })); controller.start(); String tip = "The Name Server boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer(); log.info(tip); System.out.printf(tip + "%n"); return controller; } catch (Throwable e) { e.printStackTrace(); System.exit(-1); } return null; } public static Options buildCommandlineOptions(final Options options) { Option opt = new Option("c", "configFile", true, "Name server config properties file"); opt.setRequired(false); options.addOption(opt); opt = new Option("p", "printConfigItem", false, "Print all config item"); opt.setRequired(false); options.addOption(opt); return options; } }
sh ${ROCKETMQ_HOME}/bin/runserver.sh com.alibaba.rocketmq.namesrv.NamesrvStartup $@--------上面这行代码是bin目录下的mqnamesrv文件中的命令,执行NamesrvStartup 的Main方法,启动nameServer,既然是用netty作为io框架来做服务端,必然有netty两个线程池的eventloop
@Override------------NettyRemotingServer的start方法,eventLoopGroupBoss是父线程池,管理端口监控连接的,eventLoopGroupSelector 是子线程池,select channel的读写,处理业务逻辑的 public void start() { this.defaultEventExecutorGroup = new DefaultEventExecutorGroup( nettyServerConfig.getServerWorkerThreads(), new ThreadFactory() { private AtomicInteger threadIndex = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { return new Thread(r, "NettyServerCodecThread_" + this.threadIndex.incrementAndGet()); } }); ServerBootstrap childHandler = this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector) .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .option(ChannelOption.SO_REUSEADDR, true) .option(ChannelOption.SO_KEEPALIVE, false) .childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize()) .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize()) .localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))-----------根据之前分析netty可以知道,initchannel方法中添加的handler,每一个channel在accept生成的时候,都会把childHandler给添加到自己的pipeline当中去,当然initChannel方法中的handler也会添加进去,这几个handler一定有处理服务注册和服务发现相关逻辑的。 .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, new HandshakeHandler(TlsSystemConfig.tlsMode)) .addLast(defaultEventExecutorGroup,//这里用的netty的第三个线程池,把channel的读写和在pipeline中的数据处理分开-----------------Encoder和Decoder的encode/decode方法之所以能使用,是被继承的适配器中的channelread/write调用了 new NettyEncoder(), new NettyDecoder(),-----------------------检测心跳,长时间没有数据的连接关闭掉 new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),-----------------------------重写了register,active等方法 new NettyConnectManageHandler(),-----------------------------核心的数据处理类,明天再看 new NettyServerHandler() ); } }); if (nettyServerConfig.isServerPooledByteBufAllocatorEnable()) { childHandler.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); } try { ChannelFuture sync = this.serverBootstrap.bind().sync(); InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress(); this.port = addr.getPort(); } catch (InterruptedException e1) { throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1); } if (this.channelEventListener != null) { this.nettyEventExecutor.start(); } this.timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { NettyRemotingServer.this.scanResponseTable(); } catch (Throwable e) { log.error("scanResponseTable exception", e); } } }, 1000 * 3, 1000); }