Namesrv简介
Broker
启动时,会向所有的Nameserver
注册。
消息生产者发送消息前,先去Nameserver
拉取broker
服务器地址列表。然后根据负载均衡算法选择一台Broker
进行消息发送。
NameServer
与Broker
保持长连接,并每隔30s检测Broker
是否存活。
如果检测到Broker
宕机,则从路由列表中将其移除。但不会马上通知消息生产者。而是在消息发送端提供容错机制来保证消息发送的高可用性。
NameServer
集群之间并不互相通信,路由信息并非是强一致性。
NameServer启动流程
-
加载配置文件
// NamesrvConfig final NamesrvConfig namesrvConfig = new NamesrvConfig(); // NettyServerConfig 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, %s%n", file); in.close(); } }
NameServerConfig
的配置来源有两个:- 通过
-c
指定配置文件路径 - 使用
-- 属性名 属性值
来设置,如--listenPort 9876
NamesrvConfig
public class NamesrvConfig { private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY, System.getenv(MixAll.ROCKETMQ_HOME_ENV)); private String kvConfigPath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "kvConfig.json"; private String configStorePath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "namesrv.properties"; private String productEnvName = "center"; private boolean clusterTest = false; private boolean orderMessageEnable = false; }
rocketmqHome
:rocketmq主目录,配置环境变量kvConfigPath
:存储KV配置的默认路径configStorePath
:nameserver
默认配置文件路径orderMessageEnable
:是否支持顺序消息
NettyServerConfig
public class NettyServerConfig implements Cloneable { private int listenPort = 8888; private int serverWorkerThreads = 8; private int serverCallbackExecutorThreads = 0; private int serverSelectorThreads = 3; private int serverOnewaySemaphoreValue = 256; private int serverAsyncSemaphoreValue = 64; private int serverChannelMaxIdleTimeSeconds = 120; private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize; private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize; private boolean serverPooledByteBufAllocatorEnable = true; private boolean useEpollNativeSelector = false; }
listenPort
:监听端口serverWorkerThread
:Netty
业务线程池线程个数serverCallbackExecutorThreads
:Netty
公共的线程池线程个数。如果业务类型没有指定线程池,则由public
线程池执行serverSelectorThreads
:IO线程池线程个数。用于解析请求,然后将任务转发给对应的业务类型,再将结果返回给调用方。serverOnewaySemaphoreValue
:send oneway
消息请求并发度(Broker
)serverAsyncSemaphoreValue
:异步消息发送的最大并发度(Broker
)serverChannelMaxIdleTimeSeconds
:网络连接的最大空闲时间,如果连接空闲时间操作此数,连接将被关闭serverSocketSndBufSize
:网络socket
发送缓存区大小,默认64k
serverSocketRcvBufSize
:网络socket
接收缓存区大小,默认64k
serverPooledByteBufAllocatorEnable
:ByteBuffer
是否开启缓存useEpollNativeSelector
:是否启用Epoll IO
模型,Linux建议开启
- 通过
-
根据启动属性创建
NamesrvController
,并初始化改实例。public boolean initialize() { // 加载KV配置 this.kvConfigManager.load(); // 创建NameServer网络处理对象 this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService); this.remotingExecutor = Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_")); this.registerProcessor(); // 每隔10s扫描一次Broker,移除不激活的Broker this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.routeInfoManager.scanNotActiveBroker(); } }, 5, 10, TimeUnit.SECONDS); // 每10分钟打印一次KV配置 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.kvConfigManager.printAllPeriodically(); } }, 1, 10, TimeUnit.MINUTES); // 省略部分代码 return true; }
-
注册钩子函数
// 注册钩子函数 Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() { @Override public Void call() throws Exception { // 关闭线程池,释放资源 controller.shutdown(); return null; } }));
路由注册和故障剔除
NameServer
的主要作用是为消息生产者和消息消费者提供Topi