MQ系列4:NameServer 原理解析
MQ系列1:消息中间件执行原理
MQ系列2:消息中间件的技术选型
MQ系列3:RocketMQ 架构分析
1 关于NameServer
上一节的 MQ系列3:RocketMQ 架构分析,我们大致介绍了 RocketMQ的基本组件构成,包括 NameServer、Broker、Producer以及Consumer四部分。
NameServer,指的是服务可以根据给定的名字来进行资源或对象的地址定位,并获取有关的属性信息。在Rocket中也一样,NameServer是 RocketMQ 的服务注册中心(类似于 Kafka 集群 后面的 Zookeeper 集群一样, 对集群元数据进行管理),根据元数据(ip、port和router信息)来唯一定位服务。RocketMQ 需要先启动 NameServer ,再启动 Rocket 中的 Broker。
2 NameServer运行流程
2.1 注册
注册发生在Broker启动之后,启动后快速与NameServer建立长连接,并每30s对NameService发送一次心跳包,Broker会将自己的IP Address、Port、Router 等信息随着心跳一并注册到 NameServer中。
这里的RouterInfo 主要指Broker下包含哪些Topic信息,这种映射关系方便后面消息的生产和消费的时候进行寻址。
注册使用到的核心数据结构如下:
HashMap<String BrokerName, BrokerData> brokerAddrTable
- HashMap 的 Key 是 Broker 的名称,存储了一个Broker服务所对应的属性信息。
- Value 是个对象,数据结构如下:
字段 | 类型 | 说明 |
---|---|---|
cluster | String | 所属的集群名称 |
broker | String | broker的名称 |
brokerAddress | HashMap | Broker的IP地址列表,包含一个Master IP地址列表 和 多个Slave IP地址列表 |
" Broker-A":{
"cluster":"Broker-Cluster",
"brokerName":"Broker-A",
"cluster":{ // 1主2从
"0":"192.168.0.1:1234",
"1":"192.168.0.2:1234",
"2":"192.168.0.3:1234"
}
}
2.2 注册信息更新
当你对你的Broker中的Topic信息进行更新了(增、删、改)怎么办,你才需要重新将信息注册到NameServer中。
- 如果你创建了新的 Topic,Broker会向 NameServer 发送注册信息,接收到信息后会对每个Master 角色的Broker ,创建一个新的QueueData对象。
- 如果你修改了Topic,则NameServer 会先把旧的 QueueData 删除,在加一个新的 QueueData。
- 如果你删除了Topic,则NameServer 会将对应的 QueueData 删除。
使用到的核心数据结构如下:
HashMap<String topic, List<QueueData>> topicQueueTable
- HashMap 的 Key 是 Topic 的名称,里面存储了Topic的所有属性信息。
- Value 是个列表,列表的数据类型是 QueueData,列表的length就是Topic中的 Master角色的 Broker 个数。
- QueueData的结构如下
字段 | 类型 | 说明 |
---|---|---|
brokerName | String | broker名称 |
readQueueNums | Long | 读Queue的数量 |
writeQueueNums | Long | 写Queue的数量 |
perm | Integer | 权限 PRIORITY = 3, READ = 2, WRITE = 1 , INHERIT = 0 |
topicSyncFlag | Long | 同步的位置标识 |
{
"topic-test":[ // topic名称,注意下面会用到
{
"brokerName":"Broker-A",
"readQueueNums":37,
"writeQueueNums":37,
"perm":6, // 读写权限
"topicSynFlag":12
},
{
"brokerName":"Broker-B",
"readQueueNums":37,
"writeQueueNums":37,
"perm":6, // 读写权限
"topicSynFlag":12
}
]
}
参考RocketMQ源码如下,这边加了注释,方便理解:
/**
* 创建或者更新 MessageQueue 的数据
* @param brokerName
* @param topicConfig
*/
private void createAndUpdateQueueData(final String brokerName, final TopicConfig topicConfig) {
QueueData queueData = new QueueData();
queueData.setBrokerName(brokerName); // broker 名称
queueData.setWriteQueueNums(topicConfig.getWriteQueueNums()); // 读Queue的数量
queueData.setReadQueueNums(topicConfig.getReadQueueNums()); // 写Queue的数量
queueData.setPerm(topicConfig.getPerm()); // 权限: PRIORITY = 3, READ = 2, WRITE = 1 , INHERIT = 0
queueData.setTopicSynFlag(topicConfig.getTopicSysFlag());
List<QueueData> queueDataList = this.topicQueueTable.get(topicConfig.getTopicName());
if (null == queueDataList) { // 新增
queueDataList = new LinkedList<QueueData>();
queueDataList.add(queueData);
this.topicQueueTable.put(topicConfig.getTopicName(), queueDataList);
log.info("new topic registerd, {} {}", topicConfig.getTopicName(), queueData);
} else { // 更新
boolean addNewOne = true;
Iterator<QueueData> it = queueDataList.iterator();
while (it.hasNext()) {
QueueData qd = it.next();
if (qd.getBrokerName().equals(brokerName)) {
if (qd.equals(queueData)) {
addNewOne = false;
} else {
log.info("topic changed, {} OLD: {} NEW: {}", topicConfig.getTopicName(), qd,
queueData);
it.remove(); // 先删除
}
}
}
if (addNewOne) {
queueDataList.add(queueData); // 再添加
}
}
}
2.3 异常清理
如果Broker挂掉,那么再被消息的生产者和消费者使用就会有问题了。这时候需要对已经宕掉的Broker进行清理,确保NamServer中注册的Broker服务信息都是Alive的。它的做法是这样的:
- 前面我们说了,Broker每30s对NameService发送一次心跳包给NameServer
- NameServer接收到心跳包的时候,会将当前时间戳更新到
brokerLiveTable
表的lastUpdateTimestamp
字段中。 - NameServer中会启动一个定时任务
- 每10s(记住这边扫描是10s间隔,与上面心跳包区分开)扫描 一下
brokerLiveTable
表 - 检查
lastUpdateTimestamp
字段,如果时间戳与当前时间相隔超过 120s(即两分钟),则认为 Broker 已经宕了,并会将broker清除出NameServer的注册表。
使用到的核心数据结构如下:
HashMap<String BrokerAddr, BrokerLiveInfo> brokerLiveTable
- HashMap 的 Key 是 Broker服务器的地址信息(IP+Port),里面存储了该Broker服务器的基本信息。
- Value 是个对象,结构如下:
字段 | 类型 | 说明 |
---|---|---|
lastUpdateTimestamp | Long | 最后一次收到心跳包的时间戳 |
dataVersion | DataVersion | 数据版本号对象 |
channel | Channel | netty的Channel,IO数据交互媒介 |
haServerAddr | String | master地址,初次请求的时候值为空,slave向NameServer注册之后返回 |
2.4 消息生产和消费
上面的步骤都完成之后,NameServer这个 "中央大脑" 正式开始投入使用。这时候 ,消息的生产和消费具体是怎么做的呢?
- Producer 或者 Consumer 启动之后会和 NameServer 建立长连接
- 定时(默认为每30s)从 NameServer 获取Routers信息,并将路由信息保存至Producer或者Consumer的本地。
- Producer发送一条消息
hello-brand
到 topic (topic-test
) 中 - 因为名称为
topic-test
的 topic 存在于多个 broker中,所以需要如下几个步骤,才能找到具体的地址:- 先 根据 topic 名称
topic-test
查询topicQueueTable
, 选择一个并获取它的broker信息(包含brokerName) - 再根据已经获取到的brokerName 查询
brokerAddressTable
获取具体的Broker IP地址(一般包含1个Master和n个Slave的IP地址) - 拿到IP地址之后,生产者与broker建立连接,并发送消息
- 消费者同理
- 先 根据 topic 名称
3 总结
上述的流程图比较清晰的描述如下运转流程:
- NameServer 作为整个 RocketMQ 的“中央大脑” ,负责对集群元数据进行管理,所以 RocketMQ 需要先启动 NameServer 再启动 Rocket 中的 Broker。
- Broker 启动后,与 NameServer 保持长连接,每 30s 发送一次发送心跳包,来确保Broker是否存活。并将 Broker 信息 ( IP+、端口等信息)以及Broker中存储的Topic信息上报。注册成功后,NameServer 集群中就有 Topic 跟 Broker 的映射关系。
- NameServer有个定时任务,每10s扫描下
brokerLiveTable
表 , 如果检测到某个Broker 宕机(因为使用心跳机制, 如果检测超120s(两分钟)无上报心跳),则从路由注册表中将其移除。 - 生产者在发送某个主题的消息之前先从 NamerServer 获取 Broker 服务器地址列表(通过topic名称查询
topicQueueTable
获得broker名称,通过broker名称查询brokerAddressTable
获取具体的Broker IP地址),然后根据负载均衡算法从列表中选择1台Broker ,建立连接通道,进行消息发送。 - 消费者在订阅某个topic的消息之前从 NamerServer 获取 Broker 服务器地址列表(同上),包括关联的全部Topic队列信息。进而获取当前订阅 Topic 存在哪些 Broker 上,然后直接跟 Broker 建立连接通道,开始消费数据。
- 生产者和消费者默认每30s 从 NamerServer 获取 Broker 服务器地址列表,以及关联的所有Topic队列信息,更新到Client本地。
参考:
https://zhuanlan.zhihu.com/p/388807516
MQ系列4:NameServer 原理解析的更多相关文章
- MQ系列5:RocketMQ消息的发送模式
MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 MQ系列4:NameServer 原理解析 在之前的篇章中,我们学习了RocketMQ的原理, ...
- MQ系列6:消息的消费
MQ系列1:消息中间件执行原理 MQ系列2:消息中间件的技术选型 MQ系列3:RocketMQ 架构分析 MQ系列4:NameServer 原理解析 MQ系列5:RocketMQ消息的发送模式 在之前 ...
- java基础解析系列(七)---ThreadLocal原理分析
java基础解析系列(七)---ThreadLocal原理分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)-- ...
- java基础解析系列(六)---注解原理及使用
java基础解析系列(六)---注解原理及使用 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---Integer缓存及 ...
- Spring Boot干货系列:(三)启动原理解析
Spring Boot干货系列:(三)启动原理解析 2017-03-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说 ...
- ThreadLocal系列(三)-TransmittableThreadLocal的使用及原理解析
ThreadLocal系列(三)-TransmittableThreadLocal的使用及原理解析 上一篇:ThreadLocal系列(二)-InheritableThreadLocal的使用及原理解 ...
- ThreadLocal系列(二)-InheritableThreadLocal的使用及原理解析
ThreadLocal系列之InheritableThreadLocal的使用及原理解析(源码基于java8) 上一篇:ThreadLocal系列(一)-ThreadLocal的使用及原理解析 下一篇 ...
- ThreadLocal系列(一)-ThreadLocal的使用及原理解析
ThreadLocal系列之ThreadLocal(源码基于java8) 项目中我们如果想要某个对象在程序运行中的任意位置获取到,就需要借助ThreadLocal来实现,这个对象称作线程的本地变量,下 ...
- android黑科技系列——应用市场省流量更新(增量升级)原理解析
一.前言 最近在看热修复相关的框架,之前我们已经看过了阿里的Dexposed和AndFix这两个框架了,不了解的同学可以点击这里进行查看:Dexposed框架原理解析 和 AndFix热修复框架原理解 ...
随机推荐
- Hyper-v安装虚拟机,提示the image's hash and certificate are not allowed错误的解决方法
本文迁移自Panda666原博客,原发布时间:2021年3月29日. Hyper-v安装虚拟机,提示the image's hash and certificate are not allowed错误 ...
- BUUCTF-佛系少年
佛系少年 这题我感觉超扯,不知道当时环境是不是断网的,断网咋解密的出来.. 下载后有个压缩包,带加密的,首先16进制看看是否是真加密 这里可以看到,压缩包数据区这里都是未加密的方式 但是到了压缩包目录 ...
- (win环境)使用Electron打造一个桌面应用翻译小工具
初始化项目 npm init 修改package.json {"name": "trans","version": "1.0.0& ...
- canvas简易画布
今天学习了canvas,利用它做了一个简易版的画板,校验自己所学的知识,分享出来以供大家学习指教.先上效果图. 主要是使用了canvas的stroke和clearReact来实现画板的绘画和橡皮擦功能 ...
- 一文掌握GitHub Actions基本概念与配置
CI/CD包含很多流程,如拉取代码.测试.构建打包.登录远程服务器.部署发布等等. 而Github Actions是GitHub推出的一个CI/CD工具,类似工具还有TravisCI.Jenkins等 ...
- UiPath官网认证中文教程
RPA之家公众号:RPA之家 RPA之家官网:http://rpazj.com 斗鱼直播:http://www.douyu.com/rpazj UiPath中文社区QQ群:465630324 RPA& ...
- 【计算机系统基础1】gdb、gcc简易使用指南
目录 1. 基本实验工具的使用 1.1GCC 在IA-32+LINUX平台 基本的GCC 命令 一些其他选项 1.2objdump 1.3gdb 启动gdb 调试工具 设置断点 启动程序运行 查看程序 ...
- 『现学现忘』Git后悔药 — 28、版本回退git reset --soft命令说明
git reset --soft commit-id命令:回退到指定版本.(soft:柔软的) 该命令仅仅修改分支中的HEAD指针的位置,不会改变工作区与暂存区中的文件的版本. 实现上是只做了一件事情 ...
- 写出个灵活的系统竟然可以如此简单!小白也能写出高级的Java业务!
一 最近正好公司里有个需求,一个短信业务接了多个第三方供应商,某些业务需要查询第三方供应商剩余的短信包数量去选择剩余量最多的渠道去批量发送.有些业务是指定了某个短信供应商,有些场景需要根据业务的值去动 ...
- 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...