NameServer架构设计
消息中间件的设计思路一般是基于主题的订阅发布机制,消息生产者(Producer)发送某一主题的消息到消息服务器,消息服务器负责该消息的持久化存储,消息消费者(Consumer)订阅感兴趣的主题,消息服务器根据订阅信息(路由信息)将消息推送给消费者(推模式)或者消息消费者主动向消息服务器拉取消息(拉模式),从而实现消息生产者与消息消费者的解耦。为了避免因消息服务器的单点故障导致的整个系统瘫痪,通常会部署多台消息服务器共同承担消息的存储。那么消息生产者如何知道消息要发往哪台消息服务器呢?如果某一台消息服务器宕机了,生产者如何在不重启服务的情况下感知呢?
NameServer 就是为了解决上述问题而设计的,RocketMQ 的逻辑部署如图2-1 所示。

Broker 消息服务器在启动时向所有 NameServer 注册,消息生产者在发送消息之前先从 NameServer 获取 Broker 服务器的地址列表,然后根据负载算法从列表中选择一台消息服务器发送消息。NameServer 与每台 Broker 服务器保持长连接,并间隔 10s 检测 Broker 是否存活,如果检测到 Broker 宕机,则从路由注册表中将其移除,但是路由变化不会马上通知消息生产者。为什么要这样设计呢?这是为了降低 NameServer 实现的复杂性,因此需要在消息发送端提供容错机制来保证消息发送的高可用性,这部分在 3.4 节会有详细的描述。
NameServer 本身的高可用性可通过部署多台 NameServer 服务器来实现,但彼此之间互不通信。虽然 NameServer 服务器之间在某一时刻的数据并不会完全相同,但对消息发送不会造成重大影响,无非就是短暂造成消息发送不均衡,这也是 RocketMQ NameServer 设计的一个亮点。
NameServer 核心架构设计如图2-2 所示。

消息客户端与 NameServer、Broker 的交互设计要点如下。
-
Broker 每隔 30s 向 NameServer 集群的每一台机器发送心跳包,包含自身创建的 topic 路由等信息。
-
消息客户端每隔 30s 向 NameServer 更新对应 topic 的路由信息。
-
NameServer 收到 Broker 发送的心跳包时会记录时间戳。
-
NameServer 每隔 10s 会扫描一次 brokerLiveTable(存放心跳包的时间戳信息),如果在 120s 内没有收到心跳包,则认为 Broker 失效,更新 topic 的路由信息,将失效的 Broker 信息移除。