RocketMQ-NameServer分析

本文深入探讨RocketMQ的NameServer,重点分析其在broker管理和路由管理中的角色。NameServer接收broker的注册信息,存储在RouteInfoManager中,并处理客户端的路由请求,提供Topic的路由信息。客户端则定时请求并缓存路由信息,以便与broker通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Rocketmq中的NameServer主要负责两个工作,broker管理和路由管理。这篇文章主要是分析NameServer如何完成这两个工作的。

一、broker管理

broker会定时上报broker的基本信息以及主题信息给NameServer,NameServer会将这些信息存储到RouteInfoManager中

1. broker上报信息

我们看看broker启动时关于上报信息的代码

//位于BrokerController.start
this.registerBrokerAll(true, false, true);
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        try {
            BrokerController.this.registerBrokerAll(true, false, brokerConfig.isForceRegister());
        } catch (Throwable e) {
            log.error("registerBrokerAll Exception", e);
        }
    }
}, 1000 * 10, Math.max(10000, Math.min(brokerConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);

可以看出,broker启动的时候会立刻向NameServer注册,然后会启动定时任务(默认30s)向NameServer同步自己的注册信息。

接下来关注具体的register操作。第一步,组装上报的信息,包括broker地址、brokerId、brokerName、clusterName、主题信息等

//位于BrokerOuterAPI.registerBrokerAll
final RegisterBrokerRequestHeader requestHeader = new RegisterBrokerRequestHeader();
requestHeader.setBrokerAddr(brokerAddr);
requestHeader.setBrokerId(brokerId);
requestHeader.setBrokerName(brokerName);
requestHeader.setClusterName(clusterName);
requestHeader.setHaServerAddr(haServerAddr);
requestHeader.setCompressed(compressed);

RegisterBrokerBody requestBody = new RegisterBrokerBody();
requestBody.setTopicConfigSerializeWrapper(topicConfigWrapper);
requestBody.setFilterServerList(filterServerList);

第二步,多线程发送注册信息给所有NameServer,并使用CountDownLatch等待所有线程完成注册任务。

//位于BrokerOuterAPI.registerBrokerAll
final CountDownLatch countDownLatch = new CountDownLatch(nameServerAddressList.size());
for (final String namesrvAddr : nameServerAddressList) {
    brokerOuterExecutor.execute(new Runnable() {
        @Override
        public void run() {
            try {
                RegisterBrokerResult result = registerBroker(namesrvAddr,oneway, timeoutMills,requestHeader,body);
                if (result != null) {
                    registerBrokerResultList.add(result);
                }

                log.info("register broker to name server {} OK", namesrvAddr);
            } catch (Exception e) {
                log.warn("registerBroker Exception, {}", namesrvAddr, e);
            } finally {
                countDownLatch.countDown();
            }
        }
    });
}
try {
    countDownLatch.await(timeoutMills, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {}
2. NameServer存储broker的信息

NameServer接收到broker的register请求后,会从中取出broker信息存放在RouteInfoManager中

//位于DefaultRequestProcessor.registerBroker
final RegisterBrokerRequestHeader requestHeader = (RegisterBrokerRequestHeader)request.decodeCommandCustomHeader(RegisterBrokerRequestHeader.class);
TopicConfigSerializeWrapper topicConfigWrapper;
if (request.getBody() != null) {
    topicConfigWrapper = TopicConfigSerializeWrapper.decode(request.getBody(), TopicConfigSerializeWrapper.class);
} else {
    topicConfigWrapper = new TopicConfigSerializeWrapper();
    topicConfigWrapper.getDataVersion().setCounter(new AtomicLong(0));
    topicConfigWrapper.getDataVersion().setTimestamp(0);
}
RegisterBrokerResult result = this.namesrvController.getRouteInfoManager().registerBroker(
    requestHeader.getClusterName(),
    requestHeader.getBrokerAddr(),
    requestHeader.getBrokerName(),
    requestHeader.getBrokerId(),
    requestHeader.getHaServerAddr(),
    topicConfigWrapper,
    null,
    ctx.channel()
);

总结一下,broker管理的流程大概就是
(1)broker启动向每一台NameServer上报信息(包括broker地址、brokerId、brokerName、clusterName、主题信息等)
(2)broker定时向每一台NameServer同步信息
(3)nameServer接收broker信息后存储在RouteInfoManager中
可以知道,NameServer之间是相互独立的管理着broker的信息。

二、路由管理

客户端通过NameServer获取路由信息,然后直接与broker进行通讯。

1. 客户端请求路由信息

那什么时候会获取路由信息呢?客户端会在启动时设置一些定时任务,包括(1)定时(默认30s)获取RouteInfo(2)定时(默认30s)根据RouteInfo来剔除broker列表中掉线的实例。

//MQClientInstane.startScheduledTask
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        try {
            MQClientInstance.this.updateTopicRouteInfoFromNameServer();
        } catch (Exception e) {
            log.error("ScheduledTask updateTopicRouteInfoFromNameServer exception", e);
        }
    }
}, 10, this.clientConfig.getPollNameServerInterval(), TimeUnit.MILLISECONDS);

this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
     @Override
     public void run() {
         try {
             MQClientInstance.this.cleanOfflineBroker();
             MQClientInstance.this.sendHeartbeatToAllBrokerWithLock();
         } catch (Exception e) {
             log.error("ScheduledTask sendHeartbeatToAllBroker exception", e);
         }
     }
 }, 1000, this.clientConfig.getHeartbeatBrokerInterval(),TimeUnit.MILLISECONDS);

即使没有的及时更新主题信息,当客户端发现找不到目标主题的信息,也会主动获取并更新到本地。

2. 客户端与NameServer建立连接

客户端会与其中一台NameServer保持通讯,namesrvAddrChoosed标识着当前通讯的NameServer,长连接会缓存在channelTables中方便重用。如果与该台NameServer连接出现异常,会按序寻找下一个可用的。

//NettyRemotingClient.getAndCreateNameserverChannel
addr = this.namesrvAddrChoosed.get();
if (addr != null) {
    ChannelWrapper cw = this.channelTables.get(addr);
    if (cw != null && cw.isOK()) {
        return cw.getChannel();
    }
}
if (addrList != null && !addrList.isEmpty()) {
    for (int i = 0; i < addrList.size(); i++) {
        int index = this.namesrvIndex.incrementAndGet();
        index = Math.abs(index);
        index = index % addrList.size();
        String newAddr = addrList.get(index);

        this.namesrvAddrChoosed.set(newAddr);
        Channel channelNew = this.createChannel(newAddr);
        if (channelNew != null) {
            return channelNew;
        }
    }
}
3. NameServer响应路由请求

当NameServer收到客户端发送过来的GET_ROUTEINTO_BY_TOPIC消息后,会从RouteInfoManager中取出主题信息返回给客户端,客户端就可以直接和broker进行通讯了,至于和哪一台broker,具体由客户端来决定(写的话只允许是master,master宕掉则不可写;读的话会选取broker返回来的推荐broker值,该broker宕掉则换下一台)。

总结一下,路由的过程是
(1)客户端定时向NameServer请求客户端所关注的topic的路由信息
(2)在没有可用的路由信息时,客户端主动请求NameServer
(3)NameServer会从RouteInfoManager取出路由信息返回给客户端
(4)客户端会将路由信息缓存起来
(5)客户端具体与哪一个broker通讯,会参考broker的建议或者自行决定,NameServer只负责返回路由信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值