RocketMQ源码深度解析二之Name Server篇
来源:互联网 发布:转换视频格式的软件 编辑:程序博客网 时间:2024/06/11 01:35
前言:主要是用于管理所有的broker信息,让producer和consumer都能获取到正确的broker信息,进行业务处理。这是一个类似于zookeeper的服务治理中心。
(一)功能
1,Broker启动时候会向Namesrv发送注册请求,Namesrv接收broker的请求注册路由信息和保存活跃的broker列表,包括Master和Slave
2,用来保存所有topic和该topic所有队列的列表
3,NameServer用来保存所有broker的Filter列表
4,接收Producer和Consumer的请求,根据某个topic获取到broker的路由信息。
(二)初始化和启动过程
1,KVConfigManager类
该类会加载NameServer的配置参数,将配置参数加载保存到一个HashMap中
2,以初始化 BrokerHousekeepingService 对象为参数初始化
NettyRemotingServer 对象, BrokerHousekeepingService 对象作为该 Netty 连接中 Socket 链接的监听器( ChannelEventListener);监听与 Broker 建立的渠道的状态(空闲、关闭、异常三个状态),并调用 BrokerHousekeepingService的相应 onChannel****方法。其中渠道的空闲、关闭、异常状态均调用RouteInfoManager.onChannelDestory 方法处理。清理 RouteInfoManager 类的几个成员变量数据
3,注册默认的处理类 DefaultRequestProcessor,所有的请求均由该处理类的 processRequest 方法来处理。
4,设置两个定时任务
(1)每隔十秒钟遍历brokerLiveTable集合,查看每个broker的最后更新时间是否超过了两分钟,超过则关闭broker的渠道并清理 RouteInfoManager 类的topicQueueTable、 brokerAddrTable、 clusterAddrTable、 filterServerTable成员变量
(2)每隔 10 分钟打印一次 NameServer 的配置参数。即KVConfigManager.configTable 变量的内容。
5,启动 NameServer 的 Netty 服务端( NettyRemotingServer),监听渠道的请求信息。当收到客户端的请求信息之后会初始化一个线程,并放入线程池中进行处理,该线程调用 DefaultRequestProcessor. processRequest 方法来处理请求。
(三)处理broker的注册请求
如果收到REGISTER_BROKER请求,那么最终会调用到RouteInfoManager.registerBroker。注册完成后,返回给Broker端主用Broker的地址和主用Broker的HA服务地址
public RegisterBrokerResult registerBroker( final String clusterName, final String brokerAddr, final String brokerName, final long brokerId, final String haServerAddr, final TopicConfigSerializeWrapper topicConfigWrapper, final List<String> filterServerList, final Channel channel) { RegisterBrokerResult result = new RegisterBrokerResult(); try { try { this.lock.writeLock().lockInterruptibly(); /* 维护 RouteInfoManager.clusterAddrTable 变量; 若 Broker 集群名字不 在该 Map 变量中,则初始化一个 Set 集合,将 brokerName 存入该 Set 集合中, 然后以 clusterName 为 key 值,该 Set 集合为 values 值存入此 Map 变量中 */ Set<String> brokerNames = this.clusterAddrTable.get(clusterName); if (null == brokerNames) { brokerNames = new HashSet<String>(); this.clusterAddrTable.put(clusterName, brokerNames); } brokerNames.add(brokerName); boolean registerFirst = false; /* 维护 RouteInfoManager.brokerAddrTable 变量,该变量是维护 Broker 的名称、 ID、地址等信息的。 若该 brokername 不在该 Map 变量中,则创建 BrokerData 对象,该对象包含了 brokername,以及 brokerId 和 brokerAddr 为 K-V 的 brokerAddrs 变量;然后以 brokername 为 key 值将 BrokerData 对象存入 该 brokerAddrTable 变量中; 说明同一个 BrokerName 下面可以有多个不同 BrokerId 的 Broker 存在,表示一个 BrokerName 有多个 Broker 存在,通过 BrokerId 来区分主备 */ BrokerData brokerData = this.brokerAddrTable.get(brokerName); if (null == brokerData) { registerFirst = true; brokerData = new BrokerData(clusterName, brokerName, new HashMap<Long, String>()); this.brokerAddrTable.put(brokerName, brokerData); } String oldAddr = brokerData.getBrokerAddrs().put(brokerId, brokerAddr); registerFirst = registerFirst || (null == oldAddr); //若 Broker 的注册请求消息中 topic 的配置不为空,并且该 Broker 是主用(即 brokerId=0) if (null != topicConfigWrapper // && MixAll.MASTER_ID == brokerId) { //则根据 NameServer 存储的 Broker 版本信息来判断是否需要更新 NameServer 端的 topic 配置信息 if (this.isBrokerTopicConfigChanged(brokerAddr, topicConfigWrapper.getDataVersion())// || registerFirst) { ConcurrentMap<String, TopicConfig> tcTable = topicConfigWrapper.getTopicConfigTable(); if (tcTable != null) { for (Map.Entry<String, TopicConfig> entry : tcTable.entrySet()) { this.createAndUpdateQueueData(brokerName, entry.getValue()); } } } } //初始化 BrokerLiveInfo 对象并以 broker 地址为 key 值存入brokerLiveTable:HashMap<String/* brokerAddr */, BrokerLiveInfo>变量中 BrokerLiveInfo prevBrokerLiveInfo = this.brokerLiveTable.put(brokerAddr, new BrokerLiveInfo( System.currentTimeMillis(), topicConfigWrapper.getDataVersion(), channel, haServerAddr)); if (null == prevBrokerLiveInfo) { log.info("new broker registerd, {} HAServer: {}", brokerAddr, haServerAddr); } //对于 filterServerList 不为空的, 以 broker 地址为 key 值存入 if (filterServerList != null) { if (filterServerList.isEmpty()) { this.filterServerTable.remove(brokerAddr); } else { this.filterServerTable.put(brokerAddr, filterServerList); } } //找到该 BrokerName 下面的主用 Broker( BrokerId=0) if (MixAll.MASTER_ID != brokerId) { String masterAddr = brokerData.getBrokerAddrs().get(MixAll.MASTER_ID); if (masterAddr != null) { //主用 Broker 地址从brokerLiveTable 中获取 BrokerLiveInfo 对象,取该对象的 HaServerAddr 值 BrokerLiveInfo brokerLiveInfo = this.brokerLiveTable.get(masterAddr); if (brokerLiveInfo != null) { result.setHaServerAddr(brokerLiveInfo.getHaServerAddr()); result.setMasterAddr(masterAddr); } } } } finally { this.lock.writeLock().unlock(); } } catch (Exception e) { log.error("registerBroker Exception", e); } return result; }
(四)根据Topic获取Broker信息和topic配置信息
接收到GET_ROUTEINTO_BY_TOPIC请求之后,间接调用了RouteInfoManager.pickupTopicRouteData方法来获取Broker和topic信息。
1、获取 topic 配置信息,根据 topic 从 RouteInfoManager.topicQueueTable变量中获取 List队列, 赋值给返回对象 TopicRouteData 的QueueDatas 变量。 表示该 topic 对应的所有 topic 配置信息以及每个配置所属的 BrokerName。
2、 从上一步获取到的 List队列中获取 BrokerName 集合,该集合是去重之后的 BrokerName 集合,然后以该 BrokerName 集合的每个 BrokerName从 RouteInfoManager.brokerAddrTable 变量中获取 BrokerData 对象,将所有获取到的 BrokerData 对象集合赋值给返回对象 TopicRouteData 的 BrokerDatas集合变量。表示该 topic 是由哪些 Broker 提供的服务,以及每个 Broker 的名字、BrokerId、 IP 地址。
3、然后以“ ORDER_TOPIC_CONFIG”和请求消息中的 topic 值为参数从NamesrvController.kvConfigManager.configTable: HashMap变量中获取orderTopiconf 值(即 broker 的顺序),并赋值给TopicRouteData.orderTopicConf 变量;该 orderTopiconf 的参数格式为:以“ ;”解析成数组,数组的每个成员是以“ :”分隔的,构成数据 “ brokerName:queueNum”;最后将 TopicRouteData 对象返回给调用者
(五)为什么放弃zookeeper
(1)在RocketMQ中,topic在每个master的数据是对等的,没有哪个master有全部的topic数据,所以选举是没有意义的
(2)NameServer与NameServer直接完全没有信息同步,所以与其依赖重量级的zookeeper,不如开发轻量级的NameServer
- RocketMQ源码深度解析二之Name Server篇
- RocketMQ源码深度解析三之Broker篇
- RocketMQ源码深度解析四之Producer篇
- RocketMQ源码深度解析五之Consumer篇
- RocketMQ源码深度解析一之消息存储
- RocketMQ的name server启动源码总结
- RocketMQ——Name Server篇
- RocketMQ源码解析:Filtersrv
- RocketMQ源码解析-事务消息的二阶段提交
- tomcat源码浅析(二)之server.xml的解析
- rocketmq源码解析系列-开头
- RocketMQ源码解析:Message存储
- RocketMQ源码解析:高可用
- RocketMQ源码解析:事务消息
- RocketMQ源码解析-Producer启动
- RocketMQ源码解析-PushConsumer(1)
- RocketMQ源码解析-PushConsumer(2)
- RocketMQ源码解析-PushConsumer(3)
- Http相关知识整理
- 如何添加SSL证书实现https请求
- 40个java多线程问题总结
- nginx配置
- c语言缓存机制
- RocketMQ源码深度解析二之Name Server篇
- js如何实现网站内容禁止复制和粘贴、另存为?
- TCP/IP、Http、Socket的区别以及面试中关于网络协议常问的考点
- 21分钟 MySQL 入门教程
- Visio安装秘钥
- Excel在统计分析中的应用—第五章—统计指数-Part3- 综合指数(现期加权指数(帕氏指数))
- cxf spring
- 解决InnoDB出现“the table is full”的问题
- var ev = ev || event