namesrv作为rocketmq的服务注册管理中心,承担着重要的统一管理,链接着broker,producer,consumer之间的关系。
namesrv的启动主要有三个阶段:构造阶段 -》加载初始化 -》启动
核心代码实现在 org.apache.rocketmq.namesrv.NamesrvController中
一,构造阶段
NamesrvController构造函数
KVConfigManager初始化,接受并执行kv接口的操作
RouteInfoManager初始化,接受并执行route接口的操作
BrokerHousekeepingService初始化,主要是在netty的网络通信中,涉及到网络的事件处理,关联的处理对应的服务管理
Configuration初始化,接受配置的管理
详见源码:
public class NamesrvController { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); //nameSrv的配置 private final NamesrvConfig namesrvConfig; //netty的配置 private final NettyServerConfig nettyServerConfig; //执行单线程的任务调度,自定义编程名称 private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl( "NSScheduledThread")); //kv的配置管理 private final KVConfigManager kvConfigManager; //路由管理器,有broker的ip和队列信息,producer发送的queue信息,consumer的pull的queue信息 private final RouteInfoManager routeInfoManager; //namesrv的netty的服务端实现 private RemotingServer remotingServer; //处理接受到请求事件的回调监听服务,主要处理netty的事件 private BrokerHousekeepingService brokerHousekeepingService; private ExecutorService remotingExecutor; private Configuration configuration; private FileWatchService fileWatchService; public NamesrvController(NamesrvConfig namesrvConfig, NettyServerConfig nettyServerConfig) { this.namesrvConfig = namesrvConfig; this.nettyServerConfig = nettyServerConfig; //构造kv配置的管理 this.kvConfigManager = new KVConfigManager(this); //构造路由信息管理 this.routeInfoManager = new RouteInfoManager(); //构造网络连接事件管理 this.brokerHousekeepingService = new BrokerHousekeepingService(this); //配置 this.configuration = new Configuration( log, this.namesrvConfig, this.nettyServerConfig ); this.configuration.setStorePathFromConfig(this.namesrvConfig, "configStorePath"); }
二,加载初始化阶段
NamesrvController的预处理加载
kvConfigManager加载,将上次保存的内容重新加载到当前的内存中
remotingServer初始化,使用netty作为服务端的初始化,下一节中单独介绍rocketmq的netty
remotingExecutor初始化,线程池的隔离很明显,不同的事件用不同的线程池,不同的线程池不同的配置,最优
registerProcessor注册事件处理,内部通信都是基于请求编码,根据编码找到对应的事件处理,得到对应的结果
scheduledExecutorService调度线程池执行,主要扫描不可用的broker,并删除,有一个时间差
scheduledExecutorService调度线程池执行,主要扫描kv的配置,同时打印到指定的日志中
fileWatchService初始化,如果是安全模式,则执行加载tls的配置,同时将加载的内容设置到netty中的ssl
详见源码:
public boolean initialize() { //加载kv配置信息的当前服务内存中 this.kvConfigManager.load(); //本地的namesrv的netty服务 this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService); //处理远程服务请求的线程池 this.remotingExecutor = Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_")); //注册可以处理的业务处理器,默认的处理 this.registerProcessor(); //定时扫描不可用的broker,同时删除不可用的broker,同时打印相关日志 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.routeInfoManager.scanNotActiveBroker(); } }, 5, 10, TimeUnit.SECONDS); //定时将kv的配置信息输出到info日志中 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.kvConfigManager.printAllPeriodically(); } }, 1, 10, TimeUnit.MINUTES); if (TlsSystemConfig.tlsMode != TlsMode.DISABLED) { // Register a listener to reload SslContext try { fileWatchService = new FileWatchService( new String[] { TlsSystemConfig.tlsServerCertPath, TlsSystemConfig.tlsServerKeyPath, TlsSystemConfig.tlsServerTrustCertPath }, new FileWatchService.Listener() { boolean certChanged, keyChanged = false; @Override public void onChanged(String path) { if (path.equals(TlsSystemConfig.tlsServerTrustCertPath)) { log.info("The trust certificate changed, reload the ssl context"); reloadServerSslContext(); } if (path.equals(TlsSystemConfig.tlsServerCertPath)) { certChanged = true; } if (path.equals(TlsSystemConfig.tlsServerKeyPath)) { keyChanged = true; } if (certChanged && keyChanged) { log.info("The certificate and private key changed, reload the ssl context"); certChanged = keyChanged = false; reloadServerSslContext(); } } private void reloadServerSslContext() { ((NettyRemotingServer) remotingServer).loadSslContext(); } }); } catch (Exception e) { log.warn("FileWatchService created error, can't load the certificate dynamically"); } } return true; }
三,启动阶段
NamesrvController的启动
remotingServer的启动,netty服务端的启动,接收外部请求并处理对应的事件
fileWatchService的启动,监听tls的配置变化
详见源码:
public void start() throws Exception { this.remotingServer.start(); if (this.fileWatchService != null) { this.fileWatchService.start(); } }
核心关键点:
1,在构造器初始化时
this.brokerHousekeepingService = new BrokerHousekeepingService(this);
将当前controller的对象传递给网络事件处理服务,源码很清晰看清楚功能实现,如果有异常则清楚路由管理的对应信息
public class BrokerHousekeepingService implements ChannelEventListener { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); private final NamesrvController namesrvController; public BrokerHousekeepingService(NamesrvController namesrvController) { this.namesrvController = namesrvController; } @Override public void onChannelConnect(String remoteAddr, Channel channel) { } //如果netty的channel关闭掉,则删除对应的路由信息 @Override public void onChannelClose(String remoteAddr, Channel channel) { this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel); } //如果netty的channel异常,则删除对应的路由信息 @Override public void onChannelException(String remoteAddr, Channel channel) { this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel); } //如果netty的channel出现idle,则删除对应的路由信息 @Override public void onChannelIdle(String remoteAddr, Channel channel) { this.namesrvController.getRouteInfoManager().onChannelDestroy(remoteAddr, channel); } }
2,在加载初始化阶段,执行的注册事件处理
this.registerProcessor();
主要是怎么处理netty客户端请求的事件,每个事件都有独立的处理逻辑
private void registerProcessor() { if (namesrvConfig.isClusterTest()) { //集群测试配置的处理器 this.remotingServer.registerDefaultProcessor(new ClusterTestRequestProcessor(this, namesrvConfig.getProductEnvName()), this.remotingExecutor); } else { //正常模式的处理器 this.remotingServer.registerDefaultProcessor(new DefaultRequestProcessor(this), this.remotingExecutor); } }
只是将线程池和事件处理设置到netty的服务端上,供netty的服务端接受处理
@Override public void registerDefaultProcessor(NettyRequestProcessor processor, ExecutorService executor) { this.defaultRequestProcessor = new Pair<NettyRequestProcessor, ExecutorService>(processor, executor); }
该数据结构在用pair对的形式存储,如果获得对应的事件处理,会用特有的线程池来执行特有的事件,完全隔离
整个事件的处理在netty的handler中执行,本章只是简单说明,下一章会详细的说明netty相关事宜
3,启动阶段
this.remotingServer.start();
netty服务的启动,核心网络通信
@Override 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()); } }); //netty的服务端启动配置 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())) .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, new NettyEncoder(), new NettyDecoder(), new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()), 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); } //namesrv端的事件回调处理机制,会调用channelEventListener的事件处理 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); }
我们主要看接受网络请求的处理,NettyServerHandler
class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> { //读取网络请求 @Override protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception { processMessageReceived(ctx, msg); } }
public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception { final RemotingCommand cmd = msg; if (cmd != null) { switch (cmd.getType()) { case REQUEST_COMMAND: //处理请求类的操作 processRequestCommand(ctx, cmd); break; case RESPONSE_COMMAND: //处理响应类的操作 processResponseCommand(ctx, cmd); break; default: break; } } }
核心在处理request的处理
public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) { final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode()); final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched; final int opaque = cmd.getOpaque(); if (pair != null) { //构建异步线程操作 Runnable run = new Runnable() { @Override public void run() { try { doBeforeRpcHooks(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd); final RemotingCommand response = pair.getObject1().processRequest(ctx, cmd); doAfterRpcHooks(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd, response); //如果不是单发需要返回对应的请求唯一标识和数据 if (!cmd.isOnewayRPC()) { if (response != null) { response.setOpaque(opaque); response.markResponseType(); try { ctx.writeAndFlush(response); } catch (Throwable e) { log.error("process request over, but response failed", e); log.error(cmd.toString()); log.error(response.toString()); } } else { } } } catch (Throwable e) { log.error("process request exception", e); log.error(cmd.toString()); if (!cmd.isOnewayRPC()) { final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_ERROR, RemotingHelper.exceptionSimpleDesc(e)); response.setOpaque(opaque); ctx.writeAndFlush(response); } } } }; if (pair.getObject1().rejectRequest()) { final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY, "[REJECTREQUEST]system busy, start flow control for a while"); response.setOpaque(opaque); ctx.writeAndFlush(response); return; } try { final RequestTask requestTask = new RequestTask(run, ctx.channel(), cmd); pair.getObject2().submit(requestTask); } catch (RejectedExecutionException e) { if ((System.currentTimeMillis() % 10000) == 0) { log.warn(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) + ", too many requests and system thread pool busy, RejectedExecutionException " + pair.getObject2().toString() + " request code: " + cmd.getCode()); } if (!cmd.isOnewayRPC()) { final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY, "[OVERLOAD]system busy, start flow control for a while"); response.setOpaque(opaque); ctx.writeAndFlush(response); } } } else { String error = " request type " + cmd.getCode() + " not supported"; final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error); response.setOpaque(opaque); ctx.writeAndFlush(response); log.error(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) + error); } }
特殊说明:
pair执行服务的获取,当前的processorTable没有事件处理,只能使用默认的,也是我们第二步初始化的defaultRequestProcessor
事件的处理是异步线程处理,最终包装成RequestTask
然后使用pair的线程池去执行该异步线程,线程内部将执行结果执行会写ctx的netty中
4,我们接着看处理事件的设计,仔细看没有高深,就是判断
public class DefaultRequestProcessor implements NettyRequestProcessor { private static InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); protected final NamesrvController namesrvController; public DefaultRequestProcessor(NamesrvController namesrvController) { this.namesrvController = namesrvController; } @Override public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException { if (ctx != null) { log.debug("receive request, {} {} {}", request.getCode(), RemotingHelper.parseChannelRemoteAddr(ctx.channel()), request); } switch (request.getCode()) { //kv的操作事件处理 case RequestCode.PUT_KV_CONFIG: return this.putKVConfig(ctx, request); case RequestCode.GET_KV_CONFIG: return this.getKVConfig(ctx, request); case RequestCode.DELETE_KV_CONFIG: return this.deleteKVConfig(ctx, request); //查询数据的版本信息 case RequestCode.QUERY_DATA_VERSION: return queryBrokerTopicConfig(ctx, request); //注册broker及消除broker的操作 case RequestCode.REGISTER_BROKER: Version brokerVersion = MQVersion.value2Version(request.getVersion()); if (brokerVersion.ordinal() >= MQVersion.Version.V3_0_11.ordinal()) { return this.registerBrokerWithFilterServer(ctx, request); } else { return this.registerBroker(ctx, request); } case RequestCode.UNREGISTER_BROKER: return this.unregisterBroker(ctx, request); //获得topic及broker及offset的信息 case RequestCode.GET_ROUTEINTO_BY_TOPIC: return this.getRouteInfoByTopic(ctx, request); case RequestCode.GET_BROKER_CLUSTER_INFO: return this.getBrokerClusterInfo(ctx, request); case RequestCode.WIPE_WRITE_PERM_OF_BROKER: return this.wipeWritePermOfBroker(ctx, request); //获得topic的操作 case RequestCode.GET_ALL_TOPIC_LIST_FROM_NAMESERVER: return getAllTopicListFromNameserver(ctx, request); case RequestCode.DELETE_TOPIC_IN_NAMESRV: return deleteTopicInNamesrv(ctx, request); //获得kvlist case RequestCode.GET_KVLIST_BY_NAMESPACE: return this.getKVListByNamespace(ctx, request); //获得topic的相关信息 case RequestCode.GET_TOPICS_BY_CLUSTER: return this.getTopicsByCluster(ctx, request); case RequestCode.GET_SYSTEM_TOPIC_LIST_FROM_NS: return this.getSystemTopicListFromNs(ctx, request); case RequestCode.GET_UNIT_TOPIC_LIST: return this.getUnitTopicList(ctx, request); case RequestCode.GET_HAS_UNIT_SUB_TOPIC_LIST: return this.getHasUnitSubTopicList(ctx, request); case RequestCode.GET_HAS_UNIT_SUB_UNUNIT_TOPIC_LIST: return this.getHasUnitSubUnUnitTopicList(ctx, request); //对config的操作 case RequestCode.UPDATE_NAMESRV_CONFIG: return this.updateConfig(ctx, request); case RequestCode.GET_NAMESRV_CONFIG: return this.getConfig(ctx, request); default: break; } return null; }