RocketMQ 架构与核心概念中已经提到过Name Server的作用,这里再具体分析一下。

结构

Name Server可以存在多个实例,但是多个实例彼此之间是无关联的。但是它们的数据会相同,Broker/Producer/Consumer往Name Server写数据的时候,实际是往所有实例中去写,以此来保证多个Name Server实例间的数据一致性。通过这种简单的同构方式来获得高可用能力。

功能

为什么需要Name Server这个角色的存在?Producer、Consumer在发送、消费的消息都是与Broker打交到,那它们是怎么知道与哪个Broker去交互呢?类似这样的信息就需要从Name Server去获取。Name Server提供的最主要的功能就是Broker信息的发现、Topic路由信息的维护。Name Server承担的就是服务发现、配置分发功能。

那为什么RocketMQ中实现了Name Server,而不是选择与一个提供类似功能的第三方服务去进行集成呢?个人推测,

  • 一是因为RocketMQ这个项目发起的时候,并不存在一个可靠好用的替代者
  • 二是Name Server只需要提供这么简单的功能,没有必要引入一个复杂的第三方
  • 三是替换成第三方服务后需要调整原先实现,增加了系统的复杂度,且没有实质上的改进

Topic信息维护

Name Server提供的最重要的功能就是Topic路由信息的维护,任何发送消费的消息都归属于某个Topic,发送消费都需要和Broker打交道。Name Server维护了Topic/Broker的关联关系。Topic/Broker之间的关系则是Broker定期上报Name Server,Name Server自身定期检查Broker信息是否有效,如果Broker宕机或下线,对应的路由信息会被移除。Name Server中用于维护相关信息的代码实现主要位于RouteInfoManager,其关键用于记录的成员为,

public class RouteInfoManager {
    private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
    private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
    private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
    private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
    private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
}

Broker信息维护

其实和上面内容一样,Broker信息维护在RouteInfoManager当中,当在命令行下通过命令去操控修改某cluster或broker上配置时,都是通过Name Server先行获取实际目标地址,再来进行后续操作。

分布式KV

除了既定的Topic路由信息之外,Name Server还提供了一个分布式KV管理服务,主要由KVConfigManager、TimedKVConfigManager去维护。Name Server提供的KV主要还是用于RocketMQ自身需要的一些全局性配置。分布式的KV服务比如Redis/Memcache等也能提供相似的功能,但也没有被使用。原因推测可能一是因为在消息队列场景下,没有太多这种KV需要配置,二是不想再引入依赖。

配置

Name Server的配置项不多,除了通用的NettyServerConfig之外,其余配置项都在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;
}

主要的配置项就是两个路径。Name Server中维护的KV信息发生变更时,就会持久化到磁盘。数据保存到Name Server本地的风险就是,如果Name Server所在机器硬盘损坏,那么RocketMQ集群就不是能够立即恢复的了,因此实际使用中部署多个Name Server是必要的。对于Topic、Broker等信息,Broker会定期上报,因此无需存盘处理。这部分则是可以任意恢复的数据。