RocketMQ(三) - RemotingServer服务端启动 源码分析

RocketMQ(三) - RemotingServer服务端启动 源码分析

接着 《 RocketMQ(一) - NameServer 启动源码分析 》 文章最后留下的 RemotingServer网络层服务端启动 来进行分析。

继承体系

为了 更好的从 宏观上 分析RocketMQ 的 网络层对象,我们要将 服务端 与 客户端一起来分析继承体系。

服务端 NettyRemotingServer

客户端 NettyRemotingClient

由上面 客户端 与 服务端 类继承图 可以知道:

共同点: 继承了 NettyRemotingAbstract抽象类 , 实现了 RemotingService接口

不同点: 实现了 RemotingServerRemotingClient接口

该小结我们着重介绍 RemotingService接口 ,RemotingServer接口 下的方法作用。

到了之后讲解 有关 客户端的代码时,其中有些相同点就不会再继续赘述了。

RemotingService

public interface RemotingService {
    
    // 服务启动
    void start();

    // 服务关闭
    void shutdown();

    // 注册 RPCHook  钩子
    void registerRPCHook(RPCHook rpcHook);
}

RemotingServer

public interface RemotingServer extends RemotingService {

    /**
     *  注册处理器
     * @param requestCode   请求码
     * @param processor     处理器
     * @param executor      线程池
     *    这三者是绑定关系:
     *       根据请求的code  找到处理对应请求的处理器与线程池 并完成业务处理。
     */
    void registerProcessor(final int requestCode, final NettyRequestProcessor processor,
        final ExecutorService executor);


    /**
     *  注册缺省处理器
     * @param processor  缺省处理器
     * @param executor   线程池
     */
    void registerDefaultProcessor(final NettyRequestProcessor processor, final ExecutorService executor);

    // 获取服务端口
    int localListenPort();


    /**
     *  根据 请求码 获取 处理器和线程池
     * @param requestCode  请求码
     * @return
     */
    Pair<NettyRequestProcessor, ExecutorService> getProcessorPair(final int requestCode);

    /**
     *  同步调用
     * @param channel   通信通道
     * @param request   业务请求对象
     * @param timeoutMillis   超时时间
     * @return  响应结果封装
     */
    RemotingCommand invokeSync(final Channel channel, final RemotingCommand request,
        final long timeoutMillis) throws InterruptedException, RemotingSendRequestException,
        RemotingTimeoutException;

    /**
     *  异步调用
     * @param channel  通信通道
     * @param request  业务请求对象
     * @param timeoutMillis  超时时间
     * @param invokeCallback  响应结果回调对象
     */
    void invokeAsync(final Channel channel, final RemotingCommand request, final long timeoutMillis,
        final InvokeCallback invokeCallback) throws InterruptedException,
        RemotingTooMuchRequestException, RemotingTimeoutException, RemotingSendRequestException;


    /**
     *  单向调用 (不关注返回结果)
     * @param channel   通信通道
     * @param request   业务请求对象
     * @param timeoutMillis  超时时间
     */
    void invokeOneway(final Channel channel, final RemotingCommand request, final long timeoutMillis)
        throws InterruptedException, RemotingTooMuchRequestException, RemotingTimeoutException,
        RemotingSendRequestException;
}

以上的接口方法大致就分为两部分:

  1. 注册请求协议处理器 ( requestCode , proccessor, executor )
  2. 请求调用方法:
    1. 同步请求调用
    2. 异步请求调用
    3. 单向请求调用

上面分析了 接口中的方法, 而抽象类NettyRemotingAbstract 将在后面分析 NettyRemotingServer的时候带着去讲解。

老套路,下面来看下 NettyRemotingServer 的 属性和构造方法。

属性和构造器

public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
    private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);

  	// Netty服务端启动器
    private final ServerBootstrap serverBootstrap;
  	
    // worker组
    private final EventLoopGroup eventLoopGroupSelector;
  
    // boss组 
    private final EventLoopGroup eventLoopGroupBoss;

    // Netty服务端配置信息类
    private final NettyServerConfig nettyServerConfig;

 	// 公共线程池   (在注册协议处理器的时候,若未给处理器指定线程池,那么就是用该公共线程池)
    private final ExecutorService publicExecutor;

	
    //  Netty Channel 特殊状态监听器
    private final ChannelEventListener  channelEventListener;

  	// 定时器  (功能: 扫描 responseTable表,将过期的responseFuture移除)
    private final Timer timer = new Timer("ServerHouseKeepingService", true);

    // 用于在pipeline指定handler中 执行任务的线程池
    private DefaultEventExecutorGroup defaultEventExecutorGroup;

 	// 服务端绑定的端口
    private int port = 0;

    private static final String HANDSHAKE_HANDLER_NAME = "handshakeHandler";
    private static final String TLS_HANDLER_NAME = "sslHandler";
    private static final String FILE_REGION_ENCODER_NAME = "fileRegionEncoder";

  	
    // 用于处理 SSL 握手连接的处理器
    private HandshakeHandler handshakeHandler;
    
    // 协议编码 处理器
    private NettyEncoder encoder;
    
    // 连接管理 处理器
    private NettyConnectManageHandler connectionManageHandler;
    
    // 核心业务 处理器
    private NettyServerHandler serverHandler;


	// 参数1: nettyServerConfig  Netty服务端配置信息
    // 参数2: channelEventListener  channel特殊状态监听器
    public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
        final ChannelEventListener channelEventListener) {
		
        // 调用父类  就是通过 Semaphore 设置请求并发限制
        // 1. 设置 单行请求的并发限制
        // 2. 设置 异步请求的并发限制
        super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());

		
        
        this.serverBootstrap = new ServerBootstrap();
        this.nettyServerConfig = nettyServerConfig;
        this.channelEventListener = channelEventListener;


       
        // 创建公共线程池 publicExecutor   线程数量为:4
        int publicThreadNums = nettyServerConfig.getServerCallbackExecutorThreads();
        if (publicThreadNums <= 0) {
            publicThreadNums = 4;
        }
        this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
            private AtomicInteger threadIndex = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "NettyServerPublicExecutor_" + this.threadIndex.incrementAndGet());
            }
        });

    
        
        // 下面就是根据操作系统平台来选择创建 bossGroup 和 workGroup的逻辑
        if (useEpoll()) {
            this.eventLoopGroupBoss = new EpollEventLoopGroup(1, new ThreadFactory() {
                private AtomicInteger threadIndex = new AtomicInteger(0);

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyEPOLLBoss_%d", this.threadIndex.incrementAndGet()));
                }
            });

            this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
                private AtomicInteger threadIndex = new AtomicInteger(0);
                private int threadTotal = nettyServerConfig.getServerSelectorThreads();

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
                }
            });
        } else {
            this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() {
                private AtomicInteger threadIndex = new AtomicInteger(0);

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyNIOBoss_%d", this.threadIndex.incrementAndGet()));
                }
            });

            this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
                private AtomicInteger threadIndex = new AtomicInteger(0);
                private int threadTotal = nettyServerConfig.getServerSelectorThreads();

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
                }
            });
        }
		
        
        // 加载SSL连接的相关方法 (不在本篇的分析范围内)
        loadSslContext();
    }
}

上述代码中,构造方法 实际上就是为 一些属性变量附上了值:

  1. 父类的属性 semaphoreOneway , **semaphoreAsync ** 用来控制请求并发量的
  2. serverBootstrap Netty服务器启动器
  3. nettyServerConfig Netty服务器配置信息
  4. channelEventListener Netty Channel状态监听器
  5. eventLoopGroupSelector worker组
  6. eventLoopGroupBoss boss组

在看一下父类 **NettyRemotingAbstract ** 中的 属性

public abstract class NettyRemotingAbstract {


	// 控制 单向请求的 并发量
    protected final Semaphore semaphoreOneway;

    // 控制 异步请求的 并发量
    protected final Semaphore semaphoreAsync;

	// 响应对象映射表  (key: opaque  value:responseFuture)
    protected final ConcurrentMap<Integer /* opaque */, ResponseFuture> responseTable =
        new ConcurrentHashMap<Integer, ResponseFuture>(256);

	// 请求处理器映射表 (key: requestCode  value:(processor,executor)  )
    protected final HashMap<Integer/* request code */, Pair<NettyRequestProcessor, ExecutorService>> processorTable =
        new HashMap<Integer, Pair<NettyRequestProcessor, ExecutorService>>(64);

	// Netty事件监听线程池
    protected final NettyEventExecutor nettyEventExecutor = new NettyEventExecutor();

	
    // 默认的请求处理器对  包含(processor,executor) 
    protected Pair<NettyRequestProcessor, ExecutorService> defaultRequestProcessor;
	
    // SSL相关
    protected volatile SslContext sslContext;

	
    // 扩展钩子
    protected List<RPCHook> rpcHooks = new ArrayList<RPCHook>();
}

在父类中 存储的 是相对 更加业务层的 对象,其中有两个尤为重要:

  1. responseTable 响应对象映射表
  2. processorTable 请求处理器映射表

服务器启动

之前讲解的 NameServer启动的文章中,最终留下了就是本篇 网络层服务启动的入口, NettyRemotingServer # start

    // 启动Netty 服务器
    @Override
    public void start() {
        
        // Netty pipeline中的指定 handler 采用该线程池执行
        this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(
            nettyServerConfig.getServerWorkerThreads(),
            new ThreadFactory() {

                private AtomicInteger threadIndex = new AtomicInteger(0);

                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, "NettyServerCodecThread_" + this.threadIndex.incrementAndGet());
                }
            });

        // 初始化 处理器 handler
        // 1. handshakeHandler  SSL连接
        // 2. encoder  编码器
        // 3. connectionManageHandler 连接管理器处理器
        // 4. serverHandler 核心业务处理器
        prepareSharableHandlers();
		
        // 下面就是 Netty 创建服务端启动器的固定流程 
        
        ServerBootstrap childHandler =
                // 配置服务端 启动对象
                // 配置工作组 boss 和 worker 组
            this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
                    // 设置服务端ServerSocketChannel 类型
                .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                    // 设置服务端ch选项
                .option(ChannelOption.SO_BACKLOG, 1024)
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.SO_KEEPALIVE, false)
                    // 设置客户端ch选项
                .childOption(ChannelOption.TCP_NODELAY, true)
                    // 设置 接收缓冲区 和 发送缓冲区的 大小
                .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
                .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())

                    // 设置服务器端口
                .localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))

                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
          // 初始化 客户端ch pipeline 的逻辑, 同时指定了线程池为 defaultEventExecutorGroup
                        ch.pipeline()
                            .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, handshakeHandler)
                            .addLast(defaultEventExecutorGroup,
                                encoder,
                                new NettyDecoder(),
                                new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
                                connectionManageHandler,
                                serverHandler
                            );
                    }
                });

		
        if (nettyServerConfig.isServerPooledByteBufAllocatorEnable()) {
            // 客户端开启 内存池,使用的内存池 是 PooledByteBufAllocator.DEFAULT
            childHandler.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        }

        try {
            //  服务器 绑定端口
            ChannelFuture sync = this.serverBootstrap.bind().sync();
            InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress();
            this.port = addr.getPort();
        } catch (InterruptedException e1) {
            throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1);
        }

        // 条件成立: channel状态监听器不为空, 则创建 网络异常事件执行器
        if (this.channelEventListener != null) {
            this.nettyEventExecutor.start();
        }

        // 提交定时任务,每一秒 执行一次
        // 扫描 responseTable 表, 将过期的 responseFuture 移除
        this.timer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                try {
                    NettyRemotingServer.this.scanResponseTable();
                } catch (Throwable e) {
                    log.error("scanResponseTable exception", e);
                }
            }
        }, 1000 * 3, 1000);
    }

上述代码 基本上就是 模板Netty创建服务端的代码,主要做了如下几件事:

  1. 启动Netty服务器
  2. 开启 channel状态监听线程
  3. 开启 扫描 responseFuture 的定时任务

总结

RocketMQ 的 NameServer 服务端启动, 所做的事情,全都总结为下图:

posted @ 2022-02-22 17:46  s686编程传  阅读(218)  评论(0编辑  收藏  举报