RocketMQ源码分析之NameServer

本文深入探讨RocketMQ NameServer的线程池配置,包括serverWorkerThreads、serverCallbackExecutorThreads和serverSelectorThreads等,解析其在处理Broker、Producer、Consumer交互中的角色。同时,分析了服务端的并发控制参数serverOnewaySemaphoreValue和serverAsyncSemaphoreValue。文章还提及NameServer作为RocketMQ注册中心的角色和存储信息的方式。

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

1、 serverWorkerThreads

含义:业务线程池的线程个数,RocketMQ 按任务类型,每个任务类型会拥有一个专门的线程池,比如发送消息,消费消息,另外再加一个其他线程池(默认的业务线程池)。默认业务线程池,采用 fixed 类型,其线程名称:RemotingExecutorThread_。

作用范围:该参数目前主要用于 NameServer 的默认业务线程池,处理诸如 broker、producer,consume 与 NameServer 的所有交互命令。

源码来源:org.apache.rocketmq.namesrv.NamesrvController

public boolean initialize() {

        this.kvConfigManager.load();

        this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);

        this.remotingExecutor =
            Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_"));   // @1

        this.registerProcessor();                 // @2

        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                NamesrvController.this.routeInfoManager.scanNotActiveBroker();
            }
        }, 5, 10, TimeUnit.SECONDS);

        this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                NamesrvController.this.kvConfigManager.printAllPeriodically();
            }
        }, 1, 10, TimeUnit.MINUTES);

        return true;
    }

    private void registerProcessor() {
        if (namesrvConfig.isClusterTest()) {

            this.remotingServer.registerDefaultProcessor(new ClusterTestRequestProcessor(this, namesrvConfig.getProductEnvName()),
                this.remotingExecutor);
        } else {

            this.remotingServer.registerDefaultProcessor(new DefaultRequestProcessor(this), this.remotingExecutor);
        }

代码@1,创建一个线程容量为 serverWorkerThreads 的固定长度的线程池,该线程池供 DefaultRequestProcessor 类使用,实现具体的默认的请求命令处理。

代码@2,就是将 DefaultRequestProcessor 与代码@1创建的线程池绑定在一起。

具体的命令调用类:org.apache.rocketmq.remoting.netty.NettyRemotingAbstract。

/**
     * Process incoming request command issued by remote peer.
     * @param ctx channel handler context.
     * @param cmd request command.
     */
    public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
        final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
        final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
        final int opaque = cmd.getOpaque();

        if (pair != null) {
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    try {
                        RPCHook rpcHook = NettyRemotingAbstract.this.getRPCHook();
                        if (rpcHook != null) {
                            rpcHook.doBeforeRequest(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd);
                        }

                        final RemotingCommand response = pair.getObject1().processRequest(ctx, cmd);
                        if (rpcHook != null) {
                            rpcHook.doAfterResponse(RemotingHelper.parseChannelRemoteAddr(ctx.channel()), cmd, response);
                        }

                        if (!cmd.isOnewayRPC()) {
                            if (response != null) {
                                response.setOpaque(opaque);
                                response.markResponseType();
                                try {
                                    ctx.writeAndFlush(response);
                                } catch (Throwable e) {
                                    PLOG.error("process request over, but response failed", e);
                                    PLOG.error(cmd.toString());
                                    PLOG.error(response.toString());
                                }
                            } else {

                            }
                        }
                    } catch (Throwable e) {
                        PLOG.error("process request exception", e);
                        PLOG.error(cmd.toString());

                        if (!cmd.isOnewayRPC()) {
                            final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_ERROR, //
                                RemotingHelper.exceptionSimpleDesc(e));
                            response.setOpaque(opaque);
                            ctx.writeAndFlush(response);
                        }
                    }
                }
            };

            if (pair.getObject1().rejectRequest()) {
                final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY,
                    "[REJECTREQUEST]system busy, start flow control for a while");
                response.setOpaque(opaque);
                ctx.writeAndFlush(response);
                return;
            }

            try {
                final RequestTask requestTask = new RequestTask(run, ctx.channel(), cmd);
                pair.getObject2().submit(requestTask);
            } catch (RejectedExecutionException e) {
                if ((System.currentTimeMillis() % 10000) == 0) {
                    PLOG.warn(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) //
                        + ", too many requests and system thread pool busy, RejectedExecutionException " //
                        + pair.getObject2().toString() //
                        + " request code: " + cmd.getCode());
                }

                if (!cmd.isOnewayRPC()) {
                    final RemotingCommand response = RemotingCommand.createResponseCommand(RemotingSysResponseCode.SYSTEM_BUSY,
                        "[OVERLOAD]system busy, start flow control for a while");
                    response.setOpaque(opaque);
                    ctx.writeAndFlush(response);
                }
            }
        } else {
            String error = " request type " + cmd.getCode() + " not supported";
            final RemotingCommand response =
                RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error);
            response.setOpaque(opaque);
            ctx.writeAndFlush(response);
            PLOG.error(RemotingHelper.parseChannelRemoteAddr(ctx.channel()) + error);
        }

该方法比较简单,该方法其实就是一个具体命令的处理模板(模板方法),具体的命令实现由各个子类实现,该类的主要责任就是将命令封装成一个线程对象,然后丢到线程池去执行。

2、serverCallbackExecutorThreads

含义:Netty public 任务线程池格式。线程名称:NettyServerPublicExecutor_。

源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。

3、serverSelectorThreads

含义:Netty IO 线程个数,Selector 所在的线程个数,也就主从 Reactor 模型中的从 Reactor 线程数量 。

线程名称:NettyServerNIOSelector_。

作用范围:broker,product,consume 服务端的IO线程数量。

源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。

4、serverOnewaySemaphoreValue、 serverAsyncSemaphoreValue

含义:服务端 oneWay(单向执行)、异步调用的信号量(并发度)。

源码来源:org.apache.rocketmq.remoting.netty.NettyRemotingServer。

org.apache.rocketmq.remoting.netty.NettyRemotingAbstract:

备注:单向(Oneway)发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。

应用场景适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

5、 其他配置参数

// 通道空闲时间,默认120S, 通过Netty的IdleStateHandler实现
private int serverChannelMaxIdleTimeSeconds = 120;    


// socket发送缓存区大小
private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;  

// socket接收缓存区大小
private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;  

// 是否使用PooledByteBuf(可重用,缓存ByteBuf)

本文关主要分析了 Nameserver 作为 RocketMQ 的注册中心,主要存储了哪些信息,如何存储以及其核心参数。


备注:本文是《RocketMQ技术内幕》的前期素材,建议关注笔者的书籍:《RocketMQ技术内幕》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值