RocketMQ路由中心NameServer
NameServer架构设计
Producer同一时间,与NameServer集群中其中一台建立长连接。
Producer与Broker之间的Master保持长连接。
Consumer同一时间与NameServer集群中一台建立长连接。
Consumer与所有Broker建立长连接。
Producer发送某一主题的消息到消息服务器,消息服务器负责该消息的持久化存储。消息生产者(Producer)在发送消息之前先从NameServer获取Broker服务器地址列表,然后根据负载算法从列表中选择一台消息服务器进行消息发送。
Consumer订阅感兴趣的主题,消息服务器根据订阅信息(路由信息)将消息推送到消费者(PUSH模式)或者消息消费者主动向消费服务器拉取消息(PULL模式),从而实现消息生产者和消息消费者解耦。
Broker消息服务器在启动时向所有NameServer注册。Broker 部署相对复杂,Broker 分为 Master 不 Slave,一个 Master 可以对应多个 Slave,但是一个 Slave 只能 对应一个 Master,Master 与 Slave 的对应关系通过指定相同的 BrokerName,不同的 BrokerId 来定义,BrokerId为 0 表示 Master,非 0 表示 Slave。Master 也可以部署多个。每个 Broker 与 Name Server 集群中的所有节 点建立长连接,定时注册 Topic 信息到所有 Name Server。
NameServer和每台Broker服务器保持长连接,并间隔30s检测Broker是否存活。如果检测到Broker宕机,则从路由注册表中将其移除。NameServer本身的高可用可通过部署多台NameServer服务器来实现,但彼此之间互不通信,也就是NameServer服务器之间在某一时刻的数据并不会完全相同,但这对消息发送不会造成任何影响。
NameServer启动流程
NameServer启动的主类——NamesrvStartup
1 | public static NamesrvController main0(String[] args) { |
①NamesrvController类实例化
1 | public boolean initialize() { |
②注册 NameServer 服务接受请求的处理类
1 | private void registerProcessor() { |
③请求分发processRequest
1 | // (1)RemotingCommand:自定义的协议,携带请求参数和响应(2)ChannelHandlerContext:netty的数据结构,携带channel相关的信息。 |
④RouteInfoManager类存储所有请求数据
1 | public class RouteInfoManager { |
这里的lock是ReentrantReadWriteLock非公平锁,优点在于允许多个线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相当于排它锁,提高了并发性。
这样整个NameSrv的启动就完成了。