RocketMQ学习(二):RocketMQ路由中心Nameserver

基础概念

        分布式服务SOA架构体系中会有服务注册中心,分布式服务SOA的注册中心主要提供服务调用的解析服务,指引服务调用方(消费者)找到对应的服务提供者,完成网络通信。

架构设计

       消息中间件的设计思路一般基于主题的订阅发布机制,消息生产者(Producer)发送某一主题的消息到消息服务器,消息服务器负责该消息的持久化存储,消息消费者(Consumer)订阅感兴趣的主题,消息服务器根据订阅信息(路由信息)将消息推送到消费者(PUSH模式)或者消息消费者主动向消息服务器拉取消息(PULL模式),从而实现消息生产者与消息消费者解耦。

       为了避免消息服务器的单点故障导致的整个系统瘫痪,通常会部署多台消息服务器共同承担消息的存储。

       那消息生产者如何知道消息要发往哪台消息服务器呢?如果某一台消息服务器宕机了,那么生产者如何在不重启服务的情况下感知呢?

 

 

  Broker消息服务器在启动时向所有NameServer注册,消息生产者(Producer)在发送消息之前先从Nameserver获取Broker服务器地址列表,然后根据负载算法从列表中选择一台消息服务器进行消息发送。

  Nameserver与每台Broker保持长连接,并间隔10s检测Broker是否存活,如果检测到Broker宕机,则从路由注册表中将其移除。但是路由变化不会马上通知消息生产者,为什么这样设计呢?这是为了降低Nameserver实现的复杂度,在消息发送端提供容错机制来保证消息发送的高可用性。

  Nameserver本身的高可用性是通过部署多台Nameserver服务器来实现,但彼此之间互不通信,也就是Nameserver服务器之间在某一时刻的数据并不会完全相同,但这对消息发送没有影响,这也是RocketMQ Nameserver设计的一个亮点,RocketMQ Nameserver设计追求简单高效。

启动流程

步骤一:

  加载配置文件,填充NameserverConfig、NettyServerConfig属性值。具体参数,可参考34P。

步骤二:

  根据步骤一加载的启动属性创建NamesrcController实例,并初始化该实例。

  加载配置,创建NettyServer网络处理对象,然后开始两个定时任务,在RocketMQ中此类定时任务统称为心跳检测。

    • 定时任务1:Nameserver每个10s扫描一次Broker,移除处于不活跃状态的Broker。
    • 定时任务2:Nameserver每个10分钟打印一次KV配置。

步骤三:

  注册JVM钩子函数并启动服务器,以便监听Broker、消息生产者的网络请求。

路由注册

  RocketMQ基于订阅发布机制,一个Topic拥有多个消息队列,一个Broker为每一主题默认创建4个读队列4个写队列。多个Broker组成一个集群,BrokerName由相同的多台Master-Slave架构,brokerId为0代表Master,大于0代表Slave。BrokerLiveInfo中lastUpdateTimestamp存储上次收到Broker心跳包的时间。

  • topicQueueTable:Topic消息队列路由信息,消息发送时根据路由表进行负载均衡。
  • brokerAddrTable:Broker基础信息,包含brokerName、所属集群名称、主备Broker地址。
  • clusterAddrTable:Broker集群信息,存储集群中所有Broker名称。
  • brokerLiveTable:Broker状态信息。Nameserver每次收到心跳包时会替换该信息。
  • filterServerTable:Broker上的FilterServer列表,用于类模式消息过滤。

 

   RocketMQ路由注册是通过Broker与Nameserver的心跳功能实现的。Broker启动时向集群中所有的Nameserver发送心跳请求,每个30秒向集群中Nameserver发送心跳包,Nameserver收到Broker心跳包时会更新brokerLiveTable缓存中BrokerLiveInfo的lastUpdateTimestamp,然后Nameserver每个10秒扫描brokerLiveTable,如果连续120秒没有收到心跳包,Namserver将移除该Broker的路由信息,同时关闭Socket连接。

Broker心跳包发送:

  发送心跳包,首先封装请求包头:

  • brokerAddr:broker地址
  • brokerId:Master是0,Slave是1
  • brokerName:broker名称
  • clusterName:集群名称
  • haServerAddr:master地址,初次请求为空,slave向Nameserver注册后返回
  • 其他

Nameserver处理心跳包:

步骤一:

  路由注册需要加写锁,防止并发修改RouteInfoManager(路由管理)中的路由表。首先判断Broker所属集群是否存在,如果不存在,则创建,然后将broker名加入到集群Broker集合中。

步骤二:

  维护BrokerData信息,首先从brokerAddrTable根据BrokerName尝试获取Broker信息,如果不存在,则新建BrokerData并放入brokerAddrTable。

步骤三:

  如果Broker是Master,并且Broker Topic配置信息发生变化或者是初次注册,则需要创建或更新Topic路由元数据,填充topicQueueTable,其实就是为默认主题自动注册路由信息。

 步骤四:

  更新BrokerLiveInfo,保留存活的Broker,删除失效Broker。

步骤五:

  注册Broker的过滤器Server地址列表。

总结:

  Nameserver与Broker保持长连接,Broker状态存储在brokerLiveTable中,NameServer每收到一个心跳包,将更新brokerLiveTable中关于Broker的状态信息以及路由表(topicQueueTable、brokerAddrTable、brokerLiveTable、filterServerTable)。

故障剔除

  Broker每个30秒向NameServer发送一个心跳包,心跳包中包含BrokerId、Broker地址、Broker名称、Broker所属集群名称、Broker关联的FilterServer列表。

  但如果Broker宕机,Nameserver无法收到心跳包,此时Nameserver如何来剔除这些失效的Broker呢?

  RocketMQ有两个触发点来触发路由删除:

  • Nameserver定时扫描brokerLiveTable检测上次心跳包与当前系统时间差,如果时间差大于120秒,则需要移除该Broker信息。
  • Broker在正常被关闭的情况下,会执行unregisterBroker指令

步骤一:

  申请写锁,根据brokerAddress从brokerLiveTable、filterServerTable移除

步骤二:

  维护brokerAddrTable。

步骤三:

  根据BrokerName,从clusterAddrTable中找到Broker并从集群中移除。

步骤四:

  根据brokerName,遍历所有主题的队列,如果队列中包含了当前Broker的队列,则移除

步骤五:

  释放锁,完成路由删除

一图以言之:

 

posted on 2021-08-17 15:19  yssd  阅读(303)  评论(0)    收藏  举报

导航