Namesrv简介
Namesrv可以理解为一个注册中心,类似于kafka的zookeeper,但是比zk更加轻量,主要包含两块功能:
- 管理一些KV配置信息。
- 管理broker和topic的注册信息。
Namesrv启动过程
启动过程主要涉及NamesrvStartup和NamesrvController两个类。
执行sh mqnamesrv命令会启动NamesrvStartup类中的main方法,首先会执行createNamesrvController方法,解析命令行中的参数到各种config对象中(主要是NettyServerConfig和NamesrvConfig)。然后会使用这两个config对象创建NamesrvController实例对象。接下来执行NamesrvController 对象的initialize()、start()方法,并且配置ShutdownHook。initialize()方法中会依次执行加载所有kv配置、创建NettyServer、创建processor线程池、注册processor、使用scheduledExecutorService启动各种scheduled task(包括broker的心跳检测)。
start()方法会执行启动NettyServer。
不仅Namesrv的启动过程是这样,其他的组件启动过程也是startup/config/controller这样一个流程。
Namesrv主要组件
- KVConfigManager
定义一个HashMap configTable存储配置信息。键为namespace,值为真正存储kv信息的map,这样就可以将同样namespace的配置放入同一个map。
1 | private final HashMap<String/* Namespace */, HashMap<String/* Key */, String/* Value */>> configTable = |
使用读写锁控制配置信息的加载和读取。
1 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); |
KVConfigManager类中load()方法用于启动namesrv时通过configpath读取配置文件,再将配置存入map,另外还提供添加,删除,获取配置方法用于后续操作
- RouteInfoManager
定义五个map分别存储topic、broker、cluster、brokerliveinfo、filter信息。
1 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); |
DefaultRequestProcessor
namesrv启动时会注册processor
1 | private void registerProcessor() { |
当namesrv有请求过来时,会使用DefaultRequestProcessor去处理请求,处理过程会在线程池this.remotingExecutor中执行,通过processRequest方法处理请求,根据request中不同code进行不同处理。
1 | switch (request.getCode()) { |
其他
namesrv是无状态的,可以任意水平扩展,每一个broker都与所有namesrv保持长链接(有个scheduled task会按一定频率给所有namesrv做register broker的操作),所以namesrv之间没有主从关系,他们之间也不需要复制数据。client(producer/consumer)会随机选择一个namesrv进行连接。
client和broker中的namesrv地址有以下四种获取方式:
- 通过命令行或者配置文件设置namesrv地址。
- 在启动之前通过指定java选项rocketmq.namesrv.addr。
- 设置NAMESRV_ADDR环境变量,brokers和clients会去读取这个环境变量。
- 通过一个定时任务每两分钟去一个web服务中获取并更新namesrvaddr的列表。