本文来说下RocketMQ中的NameServer

文章目录

  • NameServer介绍
  • NameServer的作用
  • 为什么要使用NameServer
  • NameServer如何保证数据的最终一致
    • 路由注册
    • 路由剔除
    • 路由发现
  • 本文小结

NameServer介绍

Name Server 是专为 RocketMQ 设计的轻量级名称服务,具有简单、可集群横吐扩展、无状态,节点之间互不通信等特点。整个Rocketmq集群的工作原理如下图所示:

可以看到,Broker集群、Producer集群、Consumer集群都需要与NameServer集群进行通信

Broker集群:

Broker用于接收生产者发送消息,或者消费者消费消息的请求。一个Broker集群由多组Master/Slave组成,Master可写可读,Slave只可以读,Master将写入的数据同步给Slave。每个Broker节点,在启动时,都会遍历NameServer列表,与每个NameServer建立长连接,注册自己的信息,之后定时上报。

Producer集群:

消息的生产者,通过NameServer集群获得Topic的路由信息,包括Topic下面有哪些Queue,这些Queue分布在哪些Broker上等。Producer只会将消息发送到Master节点上,因此只需要与Master节点建立连接。

Consumer集群:

消息的消费者,通过NameServer集群获得Topic的路由信息,连接到对应的Broker上消费消息。注意,由于Master和Slave都可以读取消息,因此Consumer会与Master和Slave都建立连接。


NameServer的作用

不知道你们有没有接触过 ZooKeeper 和 Spring Cloud 中的 Eureka ,它其实也是一个 注册中心 ,主要提供两个功能:Broker管理 和 路由信息管理 。说白了就是 Broker 会将自己的信息注册到 NameServer 中,此时 NameServer 就存放了很多 Broker 的信息(Broker的路由表),消费者和生产者就从 NameServer 中获取路由表然后照着路由表的信息和对应的 Broker 进行通信(生产者和消费者定期会向 NameServer 去查询相关的 Broker 的信息)。


你可能会发现一个问题,NameServer 干啥用的,这不多余吗?直接 Producer 、Consumer 和 Broker 直接进行生产消息,消费消息不就好了么?但是,我们上文提到过 Broker 是需要保证高可用的,如果整个系统仅仅靠着一个 Broker 来维持的话,那么这个 Broker 的压力会不会很大?所以我们需要使用多个 Broker 来保证 负载均衡 。

如果说,我们的消费者和生产者直接和多个 Broker 相连,那么当 Broker 修改的时候必定会牵连着每个生产者和消费者,这样就会产生耦合问题,而 NameServer 注册中心就是用来解决这个问题的。

当然,RocketMQ 中的技术架构肯定不止前面那么简单,因为上面图中的四个角色都是需要做集群的。我给出一张官网的架构图,大家尝试理解一下。


第一、我们的 Broker 做了集群并且还进行了主从部署 ,由于消息分布在各个 Broker 上,一旦某个 Broker 宕机,则该Broker 上的消息读写都会受到影响。所以 Rocketmq 提供了 master/slave 的结构, salve 定时从 master 同步数据(同步刷盘或者异步刷盘),如果 master 宕机,则 slave 提供消费服务,但是不能写入消息 (后面我还会提到哦)。

第二、为了保证 HA ,我们的 NameServer 也做了集群部署,但是请注意它是 去中心化 的。也就意味着它没有主节点,你可以很明显地看出 NameServer 的所有节点是没有进行 Info Replicate 的,在 RocketMQ 中是通过 单个Broker和所有NameServer保持长连接 ,并且在每隔30秒 Broker 会向所有 Nameserver 发送心跳,心跳包含了自身的 Topic 配置信息,这个步骤就对应这上面的 Routing Info 。

第三、在生产者需要向 Broker 发送消息的时候,需要先从 NameServer 获取关于 Broker 的路由信息,然后通过 轮询 的方法去向每个队列中生产数据以达到 负载均衡 的效果。

第四、消费者通过 NameServer 获取所有 Broker 的路由信息后,向 Broker 发送 Pull 请求来获取消息数据。Consumer 可以以两种模式启动—— 广播(Broadcast)和集群(Cluster)。广播模式下,一条消息会发送给 同一个消费组中的所有消费者 ,集群模式下消息只会发送给一个消费者


为什么要使用NameServer

目前可以作为服务发现组件有很多,如etcd、consul,zookeeper等:


那么为什么rocketmq选择自己开发一个NameServer,而不是使用这些开源组件呢?

特别的,RocketMQ设计之初时参考的另一款消息中间件Kafka就使用了Zookeeper,Zookeeper其提供了Master选举、分布式锁、数据的发布和订阅等诸多功能。

事实上,在RocketMQ的早期版本,即MetaQ 1.x和MetaQ 2.x阶段,也是依赖Zookeeper的。但MetaQ 3.x(即RocketMQ)却去掉了ZooKeeper依赖,转而采用自己的NameServer。

而RocketMQ的架构设计决定了只需要一个轻量级的元数据服务器就足够了,只需要保持最终一致,而不需要Zookeeper这样的强一致性解决方案,不需要再依赖另一个中间件,从而减少整体维护成本。敏锐的同学肯定已经意识到了,根据CAP理论,RocketMQ在名称服务这个模块的设计上选择了AP,而不是CP


NameServer如何保证数据的最终一致

NameServer作为一个名称服务,需要提供服务注册、服务剔除、服务发现这些基本功能,但是NameServer节点之间并不通信,在某个时刻各个节点数据可能不一致的情况下,如何保证客户端可以最终拿到正确的数据。下面分别从路由注册、路由剔除,路由发现三个角度进行介绍。


路由注册

对于Zookeeper、Etcd这样强一致性组件,数据只要写到主节点,内部会通过状态机将数据复制到其他节点,Zookeeper使用的是Zab协议,etcd使用的是raft协议。

但是NameServer节点之间是互不通信的,无法进行数据复制。RocketMQ采取的策略是,在Broker节点在启动的时候,轮训NameServer列表,与每个NameServer节点建立长连接,发起注册请求。NameServer内部会维护一个Broker表,用来动态存储Broker的信息。

同时,Broker节点为了证明自己是存活的,会将最新的信息上报给NameServer,然后每隔30秒向NameServer发送心跳包,心跳包中包含 BrokerId、Broker地址、Broker名称、Broker所属集群名称等等,然后NameServer接收到心跳包后,会更新时间戳,记录这个Broker的最新存活时间。

NameServer在处理心跳包的时候,存在多个Broker同时操作一张Broker表,为了防止并发修改Broker表导致不安全,路由注册操作引入了ReadWriteLock读写锁,这个设计亮点允许多个消息生产者并发读,保证了消息发送时的高并发,但是同一时刻NameServer只能处理一个Broker心跳包,多个心跳包串行处理。这也是读写锁的经典使用场景,即读多写少。


路由剔除

正常情况下,如果Broker关闭,则会与NameServer断开长连接,Netty的通道关闭监听器会监听到连接断开事件,然后会将这个Broker信息剔除掉。

异常情况下,NameServer中有一个定时任务,每隔10秒扫描一下Broker表,如果某个Broker的心跳包最新时间戳距离当前时间超多120秒,也会判定Broker失效并将其移除。

特别的,对于一些日常运维工作,例如:Broker升级,RocketMQ提供了一种优雅剔除路由信息的方式。如在升级一个节Master点之前,可以先通过命令行工具禁止这个Broker的写权限,发送消息到这个Broker的请求,都会收到一个NO_PERMISSION响应,客户端会自动重试其他的Broker。

当观察到这个broker没有流量后,再将这个broker移除。


路由发现

路由发现是客户端的行为,这里的客户端主要说的是生产者和消费者。具体来说:

  • 对于生产者,可以发送消息到多个Topic,因此一般是在发送第一条消息时,才会根据Topic获取从NameServer获取路由信息。
  • 对于消费者,订阅的Topic一般是固定的,所在在启动时就会拉取。

那么生产者/消费者在工作的过程中,如果路由信息发生了变化怎么处理呢?如:Broker集群新增了节点,节点宕机或者Queue的数量发生了变化。细心的读者注意到,前面讲解NameServer在路由注册或者路由剔除过程中,并不会主动推送会客户端的,这意味着,需要由客户端拉取主题的最新路由信息。


本文小结

本文详细介绍了RocketMQ中的NameServer相关的知识与内容。

深入理解RocketMQ中的NameServer相关推荐

  1. 深入剖析RocketMQ源码-NameServer

    作者:vivo互联网服务器团队-Ye Wenhao 一.RocketMQ架构简介 1.1 逻辑部署图 (图片来自网络) 1.2 核心组件说明 通过上图可以看到,RocketMQ的核心组件主要包括4个, ...

  2. 深入理解RocketMQ延迟消息

    延迟消息是实际开发中一个非常有用的功能,本文第一部分从整体上介绍秒级精度延迟消息的实现思路,在第二部分结合RocketMQ的延迟消息实现,进行细致的讲解,点出关键部分的源码.第三步介绍延迟消息与消息重 ...

  3. 深入理解RocketMQ Rebalance机制

    本文深入的分析了RocketMQ的Rebalance机制,主要包括以下内容: Rebalance必要的元数据信息的维护 Broker协调通知机制: 消费者/启动/运行时/停止时Rebalance触发时 ...

  4. 5 张图带你理解 RocketMQ 消费者启动过程

    大家好,我是君哥. 今天来分享 RocketMQ 中一个关键的知识点,消费者的启动过程. 多数消息队列中,消费者和 Broker 通信的方式有两种,PUSH 模式和 PULL 模式: PUSH 模式: ...

  5. RocketMQ 中Topic、Tag、GroupName基本概念介绍

    本文主要介绍RocketMQ中Topic.Tag.GroupName的概念.设计初衷以及使用方法. 一.Topic 首先看看官方的定义: Topic是生产者在发送消息和消费者在拉取消息的类别.Topi ...

  6. 彻底理解js中this

    相关博文:http://blog.csdn.net/libin_1/article/details/49996815 彻底理解js中this的指向,不必硬背. 首先必须要说的是,this的指向在函数定 ...

  7. 理解oracle中连接和会话

    理解oracle中连接和会话 1.  概念不同:概念不同: 连接是指物理的网络连接. 在已建立的连接上,建立客户端与oracle的会话,以后客户端与oracle的交互都在一个会话环境中进行. 2.   ...

  8. 深入理解C++中public、protected及private用法

    深入理解C++中public.protected及private用法 这篇文章主要介绍了C++中public.protected及private用法,对于C++面向对象程序设计来说是非常重要的概念,需 ...

  9. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

最新文章

  1. 【Qt】新安装的虚拟机,使用QtCreator第一次编译时报错:g++: Command not found
  2. k8s组件批量启动、查看状态
  3. ML:MLOps系列讲解之《基于ML的软件的三个层次之02 Model: Machine Learning Pipelines 2.1~2.4》解读
  4. 升级到BigSur无法使用git和brew解决办法
  5. apache php 调优_LAMP服务器性能优化技巧之加速PHP
  6. SQL Server事务日志–第2部分–日志性能问题的主要原因
  7. 文本编辑器Vim/Neovim任意代码执行漏洞(CVE-2019-12735)
  8. himawari-8卫星叶绿素a产品、_海洋卫星眼中的台风quot;海神quot;
  9. el-select的写法
  10. IE浏览器降级详细教程
  11. imagej得到灰度图数据_北大博士教你如何从图像中获得可用的灰度数据
  12. 计算机技术了解(基础)
  13. 计算机网络按传输介质分为哪几类,计算机网络按传输介质可分为哪三类?
  14. 蘑菇街服务器信息,蘑菇街开放平台
  15. 码工成长手册:刚毕业的程序员如何快速提升自己?
  16. 2021年保育员(中级)考试及保育员(中级)免费试题
  17. 同步与异步通信的区别
  18. 当steam教育加入教学大纲之时
  19. NBA球星库里入股FTX并担任品牌大使,后者此前已签下布雷迪
  20. English Learning - L1-2 窥得大段表达门径 2022.12.8 周四

热门文章

  1. 在 eclipse 中设置每行的字数
  2. 【Cocos得知】技术要点通常的积累
  3. 利用文件扫描符恢复数据库.txt
  4. Hibernate关联关系映射-----单向一对一映射配置
  5. IE浏览器各版本的CSS Hack
  6. AAA验证和ciscorescue v4.2 验证服务器的搭建(telnet方式和级别的设置)
  7. 转载java中synchronized用法
  8. 新瓶旧酒ASP.NET AJAX(1) - 简单地过一下每个控件(ScriptManager、ScriptManagerProxy
  9. GDB 调试 Mysql 实战(一)源码编译安装
  10. JQuery 中简单的几个 类选择器 使用方法