在上一章分析了NamesrvController的构造函数时,会生成一个RouteInfoManager对象,该对象存放着整个消息集群的相关消息,所以这里单独拿出来分析。其实试想一下namesrv的功能不就是一个提供了通信功能的一个队列嘛,而RouteInfoManager保留了所有信息的路由。所以要想弄明白RocketMQ,RouteInfoManager必须要攻下。
  
  RouteInfoManager的构造函数
  
  主要提供了topic、broker、cluster、liveBroker的路由信息。
  
  public class RouteInfoManager {
  
  private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
  
  private final static long BROKER_CHANNEL_EXPIRED_TIME = 1000 * 60 * 2;
  
  // 读写锁
  
  private final ReadWriteLock lock = new ReentrantReadWriteLock();
  
  // Topic,以及对应的队列信息
  
  private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
  
  // 以Broker Name为单位的Broker集合
  
  private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
  
  // 集群以及属于该集群的Broker列表
  
  private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
  
  // 存活的Broker地址列表
  
  private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
  
  // Broker对应的Filter Server列表
  
  private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
  
  public RouteInfoManager() {
  
  this.topicQueueTable = new HashMap<String, List<QueueData>>(1024);
  
  this.brokerAddrTable = new HashMap<String, BrokerData>(128);
  
  this.clusterAddrTable = new HashMap<String, Set<String>>(32);
  
  this.brokerLiveTable = new HashMap<String, BrokerLiveInfo>(256);
  
  this.filterServerTable = new HashMap<String, List<String>>(256);
  
  }
  
  ..........省略
  
  topicQueueTable
  
  private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
  
  1
  
  存放了Topic的一个hashMap,在RocketMQ的插件中RocketMQ控制台,可以看到Topic的列表,这个就是topicQueueTable的一个可视化:
  
  查看QueueData的类信息:
  
  public class QueueData implements Comparable<QueueData> {
  
  // 队列所属的Broker名称
  
  private String brokerName;
  
  // 读队列数量
  
  private int readQueueNums;
  
  // 写队列数量
  
  private int writeQueueNums;
  
  // Topic的读写权限(2是写 4是读 6是读写)
  
  private int perm;
  
  private int topicSynFlag;
  
  点开一个一个topic的配置可以看到和上面类对应的变量:
  
  clusterAddrTable
  
  private final HashMap<String/* clusterName www.quwanyule157.com*/, Set<String/* brokerName */>> clusterAddrTable;
  
  1
  
  根据一个集群名,获得对应的一组BrokerName的列表,在可视化界面就是如下:
  
  虽然只得到了BrokerName,只要调用对应的接口就能得到Broker对应的属性值。
  
  brokerAddrTable
  
  private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
  
  1
  
  以Broker Name为Key,BrokerData为Value:
  
  public class BrokerData implements Comparable<BrokerData> {
  
  private String cluster;
  
  private String brokerName;
  
  //同一个brokerName下可以有一个Master和多个Slave,所以brokerAddrs是一个集合
  
  private HashMap<Long/* brokerId */, String/* broker address */> brokerAddrs;
  
  private final Random random = new Random();
  
  Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId来定 义,BrokerId为0 表示Master,非0 表示Slave。
  
  brokerLiveTable
  
  private final HashMap<String/*www.yongshiyule178.com brokerAddr */, BrokerLiveInfo> brokerLiveTable;
  
  1
  
  用于存放存活的Broker信息,BrokerLiveInfo:
  
  class BrokerLiveInfo {
  
  // 最后一次更新时间
  
  private long lastUpdateTimestamp;
  
  // 版本号
  
  private DataVersion dataVersion;
  
  // Netty的Channel
  
  private Channel channel;
  
  /**
  
  * HA Broker的地址
  
  * 是Slave从Master拉取数据时链接的地址,由brokerIp2+HA端口构成 */
  
  private String haServerAddr;
  
  registerBroker
  
  上面的类的解释可能还存在很多遗憾,下面以registerBroker方法,来实际操作一下上面提到类,看看注册一个Broker发生了什么:
  
  public RegisterBrokerResult registerBroker(
  
  final String clusterName,
  
  final String brokerAddr,
  
  final String brokerName,
  
  final long brokerId,
  
  final String haServerAddr,
  
  //TopicConfigSerializeWrapper比较复杂的数据结构,主要包含了broker上所有的topic信息
  
  final TopicConfigSerializeWrapper topicConfigWrapper,
  
  final List<String> filterServerList,
  
  final Channel channel) {
  
  RegisterBrokerResult result = new RegisterBrokerResult();
  
  try {
  
  try {
  
  this.lock.writeLock(www.feifanyule.cn/).lockInterruptibly(www.haom178.com);
  
  // 更新集群信息(根据集群名字,获取当前集群下面的所有brokerName)
  
  Set<String> brokerNames = this.clusterAddrTable.get(clusterName);
  
  // 如果当前集群下面brokerNames为空,则将当前请求broker加入到clusterAddrTable中
  
  if (null == brokerNames) {
  
  brokerNames = new HashSet<String>();
  
  this.clusterAddrTable.put(clusterName, brokerNames);
  
  }
  
  brokerNames.add(brokerName);
  
  boolean registerFirst = false;
  
  //获取所有的名称为brokerNamed 的brokerData,brokerData保留着了。也就是说同一个BrokerName,有可能有多条的brokerId和broker address与之对应
  
  // HashMap<Long/* brokerId */, String/* broker address */> brokerAddrs
  
  BrokerData brokerData = this.brokerAddrTable.get(brokerName);
  
  if (null == brokerData) {
  
  registerFirst = true;
  
  brokerData = new BrokerData(www.michenggw.com clusterName, brokerName, new HashMap<Long, String>());
  
  this.brokerAddrTable.put(brokerName, brokerData);
  
  }
  
  String oldAddr = brokerData.getBrokerAddrs(www.wanmeiyuele.cn).put(brokerId, brokerAddr);
  
  registerFirst = registerFirst || (null == oldAddr);
  
  // 更新Topic信息
  
  //如果topicConfigWrapper不为空,且当前brokerId == 0,即为当前broker为master
  
  //这里会判断只有master才会创建QueueData,因为只有master才包含了读写队列的信息
  
  if (null != topicConfigWrapper
  
  && MixAll.MASTER_ID == brokerId) {
  
  // 如果Topic配置信息发生变更或者该broker为第一次注册
  
  if (this.isBrokerTopicConfigChanged(brokerAddr, topicConfigWrapper.getDataVersion())
  
  || registerFirst)www.furggw.com {
  
  // 获取所有topic信息
  
  ConcurrentMap<String, TopicConfig> tcTable =
  
  topicConfigWrapper.getTopicConfigTable();
  
  if (tcTable != null) {
  
  // 遍历所有Topic
  
  for (Map.Entry<String, TopicConfig> entry : tcTable.entrySet()) {
  
  // 根据brokername及topicconfig(read、write queue数量等)新增或者更新到topicQueueTable中
  
  this.createAndUpdateQueueData(brokerName, entry.getValue());
  
  }
  
  }
  
  }
  
  }
  
  // 更新最后变更时间(将brokerLiveTable中保存的对应的broker的更新时间戳,设置为当前时间)
  
  BrokerLiveInfo prevBrokerLiveInfo = this.brokerLiveTable.put(brokerAddr,
  
  new BrokerLiveInfo(
  
  System.currentTimeMillis(),
  
  topicConfigWrapper.getDataVersion(),
  
  channel,
  
  haServerAddr));
  
  if (null == prevBrokerLiveInfo) {
  
  log.info("new broker registered, {} HAServer: {}", brokerAddr, haServerAddr);
  
  }
  
  if (filterServerList != null) {
  
  if (filterServerList.isEmpty()) {
  
  this.filterServerTable.remove(brokerAddr);
  
  } else {
  
  this.filterServerTable.put(brokerAddr, filterServerList);
  
  }
  
  }
  
  // 返回值(如果当前broker为slave节点)则将haServerAddr、masterAddr等信息设置到result返回值中
  
  if (MixAll.MASTER_ID != brokerId) {
  
  // 通过brokename的brokedate获取当前slave节点的master节点addr
  
  String masterAddr = brokerData.getBrokerAddrs().get(MixAll.MASTER_ID);
  
  if (masterAddr != null) {
  
  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;
  
  插入过程可以看如下这张图:
  
  疑惑
  
  topicQueueTable有一点不明白,为什么一个topic对应的是一个List,难道不是一个topic对应一个QueueData吗?难道可以存在相同的topic?
  
  因为每一个topic可以存在不同的broker中,不同的broker就有不同的QueueData。
  
  brokerAddrTable根据一个brokername获得一个BrokerData,可是为什么一个BrokerData中有一个hashMap的brokerAddrs呢?我能理解的是一个brokername,会有多个address和id,但是cluster为什么又是同一个呢?
  
  这是因为你理解错了,以为BrokerName是唯一的,实际上是指定多个broker为一个name,只不过指定了不同的id和addres来区分是master还是slave。

RocketMQ 源码分析 RouteInfoManager(四)的更多相关文章

  1. 【RocketMQ源码分析】深入消息存储(3)

    前文回顾 CommitLog篇 --[RocketMQ源码分析]深入消息存储(1) ConsumeQueue篇 --[RocketMQ源码分析]深入消息存储(2) 前面两篇已经说过了消息如何存储到Co ...

  2. RocketMQ 源码分析 —— Message 发送与接收

    1.概述 Producer 发送消息.主要是同步发送消息源码,涉及到 异步/Oneway发送消息,事务消息会跳过. Broker 接收消息.(存储消息在<RocketMQ 源码分析 —— Mes ...

  3. RocketMQ源码分析之从官方示例窥探:RocketMQ事务消息实现基本思想

    摘要: RocketMQ源码分析之从官方示例窥探RocketMQ事务消息实现基本思想. 在阅读本文前,若您对RocketMQ技术感兴趣,请加入RocketMQ技术交流群 RocketMQ4.3.0版本 ...

  4. 【RocketMQ源码分析】深入消息存储(2)

    前文回顾 CommitLog篇 --[RocketMQ源码分析]深入消息存储(1) MappedFile篇 --[RocketMQ源码分析]深入消息存储(3) 前文说完了一条消息如何被持久化到本地磁盘 ...

  5. Java集合源码分析(四)HashMap

    一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素 ...

  6. 插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52258434 在了解系统的activity,service,broa ...

  7. RocketMQ源码分析之RocketMQ事务消息实现原理上篇(二阶段提交)

    在阅读本文前,若您对RocketMQ技术感兴趣,请加入 RocketMQ技术交流群 根据上文的描述,发送事务消息的入口为: TransactionMQProducer#sendMessageInTra ...

  8. Docker源码分析(四):Docker Daemon之NewDaemon实现

    1. 前言 Docker的生态系统日趋完善,开发者群体也在日趋庞大,这让业界对Docker持续抱有极其乐观的态度.如今,对于广大开发者而言,使用Docker这项技术已然不是门槛,享受Docker带来的 ...

  9. 【RocketMQ源码分析】深入消息存储(1)

    最近在学习RocketMQ相关的东西,在学习之余沉淀几篇笔记. RocketMQ有很多值得关注的设计点,消息发送.消息消费.路由中心NameServer.消息过滤.消息存储.主从同步.事务消息等等. ...

随机推荐

  1. SQL基础语句汇总

    连接数据库 1 mysql -h10.20.66.32 -uroot -p123456 -h后面是mysqlServer所在地址,-u后面是用户名,-p后面是密码 查看数据库 1 show datab ...

  2. Python线程间事件通知

    Python事件机制 事件机制:这是线程间最简单的通信机制:一个线程发送事件,其他线程等待事件事件机制使用一个内部的标志,使用set方法进行使能为True,使用clear清除为falsewait方法将 ...

  3. 协议 - DNS

    目录 1 DNS 1.1 域名解析的历史:/etc/hosts, DNS, FQDN 1.2 域名解析流程: 域名架构 查询流程, DNS端口 1.3 合法 DNS :申请域查询授权 1.4 主机名交 ...

  4. MySQL 如何查看及修改数据库引擎

    MySQL 如何查看及修改数据库引擎 1.查看mysql支持的引擎有哪些 show engines 结果,如图所示: 由上图可以看出,只有InnoDB是支持事务的 2.查看当前默认的引擎 show v ...

  5. php-5.6.26源代码 - opcode列表

    文件 php-5.6.26/Zend/zend_vm_opcodes.h #ifndef ZEND_VM_OPCODES_H #define ZEND_VM_OPCODES_H BEGIN_EXTER ...

  6. pytorch中torch.nn构建神经网络的不同层的含义

    主要是参考这里,写的很好PyTorch 入门实战(四)--利用Torch.nn构建卷积神经网络 卷积层nn.Con2d() 常用参数 in_channels:输入通道数 out_channels:输出 ...

  7. 笔记-scrapy-scarpyd

    笔记-scrapy-scarpyd 1.      scrapy部署 会写爬虫之后就是部署.管理爬虫了,下面讲一下如何部署scrapy爬虫. 现在使用较多的管理工具是Scrapyd. scrapyd是 ...

  8. 基于原版Hadoop的YDB部署(转)

    YDB依赖环境准备 一.硬件环境 硬件如何搭配,能做到比较高的性价比,不存在短板.合理的硬件搭配,对系统的稳定性也很关键. 1.CPU不是核数越高越好,性价比才是关键. 经常遇到很多的企业级客户,他们 ...

  9. (B)springboot配置开发和测试环境并添加启动路径

    嗯,开发和测试环境要分离,这是一般共识(虽然我工作过的公司都没有这种分离),spring boot也可以按照配置文件的读取来做到这一点. 上图有三个application开头的配置文件,要达到能够读取 ...

  10. Quartus 11生成pof文件在AS烧写之后,程序无法启动

    1. 首先配置成AS,生成.pof文件,选择上面的图标Device 2. 选择Device and Pin Options... 3. 进入配置界面,选择如下 4. 进入下载界面,烧写.pof文件,开 ...