NameServer源码分析

NameServerController

主要属性

在这里插入图片描述

NamesrvConfig

是nameserver全局的一些配置属性,定义了从哪些运行环境的path获取配置

NettyServerConfig

定义了netty server的配置参数,包括监听端口,工作线程数量,一些阀值等

ScheduledExecutorService

执行定时任务的线程池

KVConfigManager

本地的kv存储工具,使用读写锁 + hashmap实现

RouteInfoManager

路由信息的管理类。主要属性如下

	// topic和包含topic的broker name之间的映射
   private final HashMap<String/* topic */, List<QueueData>> topicQueueTable;
   // brokerName和主从broker的映射
   private final HashMap<String/* brokerName */, BrokerData> brokerAddrTable;
   //集群名和broker名的映射。主从broker使用相同的cluster name,相同的name,不同的id,主为0,从为其他
   private final HashMap<String/* clusterName */, Set<String/* brokerName */>> clusterAddrTable;
   //每个broker的broker上报信息,和netty的channel
   private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
   //broker和对应的过滤服务器(不知道过滤服务器具体是什么)
   private final HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable;
   

RemotingServer

netty的轻量级封装,我感觉主要是为了符合面向接口设计,并且方便替换其他通信框架,当然这发生的概率很低。
Nameserver的启动主要分为两大步骤。

BrokerHousekeepingService

实现了netty的ChannelEventListener,对channel的close、exception、idle事件(不是很懂这些事件发生的场景,看来得看看netty)主动告知RouteInfoManager,调用其onChannelDestroy方法。把触发当前事件的broker从RouteInfoManager的缓存中,挨个移除。
在一个对象的状态变化时,通知依赖他的对象。这个设计有点观察者模式的味道。

remotingExecutor

netty的工作线程

Configuration

保存了一份启动nameserver 的全量配置

FileWatchService

ssl相关文件的监视器,如果ssl相关的配置文件更换,会更换netty的tls信息。
用到了很多并发控制的技巧,后面关注下。

启动流程

启动主要分为init和start两步。这个设计感觉是松耦合的设计。

init方法

主要是下面几步,还有一个tls模块的加载没贴,一般这种内网的服务,https应该都是关闭的。
在这里插入图片描述
kv.load()
这个方法会去加载在运行环境中预定义位置的property配置,一般都没有,所以略过

new NettyRemotingServer
会把netty的启动辅助类serverBootstrap创建好,保存了channelEventListener。
新建了netty的boss线程。
创建publicExecutor线程池。

remotingExecutor
这个应该应该应该是netty的worker线程

this.registerProcessor();
创建DefaultRequestProcessor 作为netty server 请求处理器。
org.apache.rocketmq.namesrv.processor.DefaultRequestProcessor#processRequest 处理所有已知request code类型的请求

定时任务
每10分钟会打印kvManager的所有配置信息

每10s执行routeInfoManager.scanNotActiveBroker()
遍历brokerLiveTable,剔除120s以上没有上报心跳的broker。
这个任务比较关键,是broker故障发现机制中一环

nameController的start方法

容易理解的start方法,启动netty server,如果运行环境启动了tls选项,会启动fileWatchService
在这里插入图片描述

remoteServer的start方法

发现新大陆
DefaultEventExecutorGroup 这个事件执行组之前没有了解过。

使用ServerBootstrap配置了netty的boss和worker线程,一些通信参数
添加了channelHandler。HandshakeHandler、encoder、NettyDecoder、IdleStateHandler、connectionManageHandler、serverHandler。
使用Timer,每秒扫描responseTable,处理过期的请求。

namserver处理请求的逻辑

nameserver处理请求的逻辑主要封装在org.apache.rocketmq.namesrv.processor.DefaultRequestProcessor#processRequest中

RemotingCommand
remotingCommand是rocketmq使用netty发送远程消息的封装体

	// 请求类型code @see RequestCode
    private int code;
    private LanguageCode language = LanguageCode.JAVA;
    private int version = 0;
    // 唯一标识
    private int opaque = requestId.getAndIncrement();
    private int flag = 0;
    private String remark;
    // 请求头中的字段
    private HashMap<String, String> extFields;
    //请求头
    private transient CommandCustomHeader customHeader;

    private SerializeType serializeTypeCurrentRPC = serializeTypeConfigInThisServer;
	//请求体
    private transient byte[] body;

processRequest

public RemotingCommand processRequest(ChannelHandlerContext ctx,
        RemotingCommand request) throws RemotingCommandException {
        switch (request.getCode()) {
            case RequestCode.PUT_KV_CONFIG:
                return this.putKVConfig(ctx, request);
            case RequestCode.GET_KV_CONFIG:
                return this.getKVConfig(ctx, request);
            case RequestCode.DELETE_KV_CONFIG:
                return this.deleteKVConfig(ctx, request);
            case RequestCode.QUERY_DATA_VERSION:
                return queryBrokerTopicConfig(ctx, request);
            case RequestCode.REGISTER_BROKER:
                Version brokerVersion = MQVersion.value2Version(request.getVersion());
                if (brokerVersion.ordinal() >= MQVersion.Version.V3_0_11.ordinal()) {
                    return this.registerBrokerWithFilterServer(ctx, request);
                } else {
                    return this.registerBroker(ctx, request);
                }
            case RequestCode.UNREGISTER_BROKER:
                return this.unregisterBroker(ctx, request);
            case RequestCode.GET_ROUTEINTO_BY_TOPIC:
                return this.getRouteInfoByTopic(ctx, request);
            case RequestCode.GET_BROKER_CLUSTER_INFO:
                return this.getBrokerClusterInfo(ctx, request);
            case RequestCode.WIPE_WRITE_PERM_OF_BROKER:
                return this.wipeWritePermOfBroker(ctx, request);
            case RequestCode.GET_ALL_TOPIC_LIST_FROM_NAMESERVER:
                return getAllTopicListFromNameserver(ctx, request);
            case RequestCode.DELETE_TOPIC_IN_NAMESRV:
                return deleteTopicInNamesrv(ctx, request);
            case RequestCode.GET_KVLIST_BY_NAMESPACE:
                return this.getKVListByNamespace(ctx, request);
            case RequestCode.GET_TOPICS_BY_CLUSTER:
                return this.getTopicsByCluster(ctx, request);
            case RequestCode.GET_SYSTEM_TOPIC_LIST_FROM_NS:
                return this.getSystemTopicListFromNs(ctx, request);
            case RequestCode.GET_UNIT_TOPIC_LIST:
                return this.getUnitTopicList(ctx, request);
            case RequestCode.GET_HAS_UNIT_SUB_TOPIC_LIST:
                return this.getHasUnitSubTopicList(ctx, request);
            case RequestCode.GET_HAS_UNIT_SUB_UNUNIT_TOPIC_LIST:
                return this.getHasUnitSubUnUnitTopicList(ctx, request);
            case RequestCode.UPDATE_NAMESRV_CONFIG:
                return this.updateConfig(ctx, request);
            case RequestCode.GET_NAMESRV_CONFIG:
                return this.getConfig(ctx, request);
            default:
                break;
        }
        return null;
    }

putKVConfig
客户端(broker consumer productor)会在KvConfigManager存放配置并持久化

public RemotingCommand putKVConfig(ChannelHandlerContext ctx,
        RemotingCommand request) throws RemotingCommandException {
        final RemotingCommand response = RemotingCommand.createResponseCommand(null);
        final PutKVConfigRequestHeader requestHeader =
            (PutKVConfigRequestHeader) request.decodeCommandCustomHeader(PutKVConfigRequestHeader.class);

        this.namesrvController.getKvConfigManager().putKVConfig(
            requestHeader.getNamespace(),
            requestHeader.getKey(),
            requestHeader.getValue()
        );

        response.setCode(ResponseCode.SUCCESS);
        response.setRemark(null);
        return response;
    }

getKVConfig
deleteKVConfig
向KvConfigManager查询配置和删除配置的方法

queryBrokerTopicConfig
这个方法不知道谁来调用的,看着像是broker来更新BrokerLiveInfo的dataversion

public RemotingCommand queryBrokerTopicConfig(ChannelHandlerContext ctx,
        RemotingCommand request) throws RemotingCommandException {
        final RemotingCommand response = RemotingCommand.createResponseCommand(QueryDataVersionResponseHeader.class);
        final QueryDataVersionResponseHeader responseHeader = (QueryDataVersionResponseHeader) response.readCustomHeader();
        final QueryDataVersionRequestHeader requestHeader =
            (QueryDataVersionRequestHeader) request.decodeCommandCustomHeader(QueryDataVersionRequestHeader.class);
        DataVersion dataVersion = DataVersion.decode(request.getBody(), DataVersion.class);

        Boolean changed = this.namesrvController.getRouteInfoManager().isBrokerTopicConfigChanged(requestHeader.getBrokerAddr(), dataVersion);
        if (!changed) {
            this.namesrvController.getRouteInfoManager().updateBrokerInfoUpdateTimestamp(requestHeader.getBrokerAddr());
        }

        DataVersion nameSeverDataVersion = this.namesrvController.getRouteInfoManager().queryBrokerTopicConfig(requestHeader.getBrokerAddr());
        response.setCode(ResponseCode.SUCCESS);
        response.setRemark(null);

        if (nameSeverDataVersion != null) {
            response.setBody(nameSeverDataVersion.encode());
        }
        responseHeader.setChanged(changed);
        return response;
    }

registerBrokerWithFilterServer
broker注册的方法。我们思考一下需要初始化哪些信息

  • 添加或者覆盖clusterAddrTable中当前broker的brokername
  • 首次注册添加,后续注册更新brokerData。
  • 如果是slave变master,则把master和自己先从brokerData移除,再添加当前的broker。
  • 如果broker有topic配置,那么会往topicQueueTable 插入注册broker的queuedata的信息。从插入的代码来看,queueData与broker的关系是一对一
  • 如果是master第一次注册或者topic的dataversion变了(fixme 什么情况下会变),找到当前topic并且是属于该broker的queueData。不存在则新增,有修改则覆盖
  • 添加或者更新brokerLiveTable中当前broker的BrokerLiveInfo
  • 当前broker没有携带filterServerList就移除filterServerTable,否则就添加
  • 如果不是master就返回master的地址
RegisterBrokerResult result = this.namesrvController.getRouteInfoManager().registerBroker(
            requestHeader.getClusterName(),
            requestHeader.getBrokerAddr(),
            requestHeader.getBrokerName(),
            requestHeader.getBrokerId(),
            requestHeader.getHaServerAddr(),
            registerBrokerBody.getTopicConfigSerializeWrapper(),
            registerBrokerBody.getFilterServerList(),
            ctx.channel());

unregisterBroker
删除注册

  • 删除brokerLiveTable中的自己
  • 删除filterServerTable中的自己
  • 删除brokerAddrTable中自己的brokerid,如果删除后是空,就把brokerdata删除
  • 如果主从都删除了,那么删除clusterAddrTable中的brokername,如果删除后是空,就把clustername删除
  • 如果主从都删除了,那么删除topicqueue中属于当前brokername的queuedata

getRouteInfoByTopic
org.apache.rocketmq.namesrv.routeinfo.RouteInfoManager#pickupTopicRouteData
根据topic去 topicQueueTable找到所有的brokername,再去brolerAddrTable找到主从的broker地址

getBrokerClusterInfo
找到nameserver管理的clusterAddrTable和brokerAddrTable

wipeWritePermOfBroker
擦除当前brokerName的所有topic的写权限

getAllTopicListFromNameserver
查询所有topic的信息
返回topicQueueTable的topic

deleteTopicInNamesrv
删除一个topic
根据topicName删除topicQueue中的entry

getKVListByNamespace
根据namespace获取kvConfigManager中的所有配置
//fixme namespace是什么概念 难道是适配k8s?

getTopicsByCluster
查询集群下的所有topic
获取clusterAddrTable中当前集群的所有brokerName,从topicQueueTable挨个找属于当前brokerName的topic

getSystemTopicListFromNs
这个方法最骚的是使用了brokerId为0时,entry是排在HashMap中table的第一个,这个特性。
获取了所有的clustername,所有的brokername,brokername的master brokerAddr

getUnitTopicList
获取topic的topicSynFlag属性是FLAG_UNIT的所有topicname

getHasUnitSubTopicList
获取topic的topicSynFlag属性是FLAG_UNIT_SUB的所有topicname

updateConfig
更新configuration这个类维护的property
nameServer中,这个类维护的是namesrvConfig,nettyServerConfig这两份配置

getConfig
查询configuration这个类维护的property

总结

NameServer处理的请求类型
来自broker的请求

  • 注册
  • 删除注册
  • 更新broker的brokerLiveTable
  • 主从切换时,更新brokerData
  • 查询kv存储
  • 移除broker的写权限

来自producer/consumer/管理界面

  • 根据topic查询broker
  • 获取所有topic
  • 获取系统的topic
  • 更新和查询nameServer的参数配置
  • 获取两种类型的topic FLAG_UNIT_SUB/FLAG_UNIT
  • 查询kv存储
  • 删除topic

疑问???
没有看到创建topic的动作?topic是创建在broker然后注册到nameServer?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值