概述
在上一节 RocketMQ源码详解 | Producer篇 · 其二:消息组成、发送链路 中,我们终于将消息发送出了 Producer,在短暂的 tcp 握手后,很快它就会进入目的 Broker。这次我们来自底向上的看下 Broker 端是如何接收然后分发处理消息,同时了解 RocketMQ 的 Broker 的线程模型。
Netty 组件
如果你还记得上一节的内容的话那应该知道,NettyRomotingAbstract
有两个实现类,分别是 NettyRemotingClient
和 NettyRemotingServer
,我们已经知道了前者的实现,现在我们再来看看后者
NettyRemotingServer
这个类很长,我们先来看它的属性
/* 引导类和dispatch线程与select线程池 */
private final ServerBootstrap serverBootstrap;
private final EventLoopGroup eventLoopGroupSelector;
private final EventLoopGroup eventLoopGroupBoss;
// 配置类
private final NettyServerConfig nettyServerConfig;
// 用来执行 callback 函数的线程池
private final ExecutorService publicExecutor;
// 自定义的 Channel 事件监听器
private final ChannelEventListener channelEventListener;
// 扫描已经超时的 ResponseFeature
private final Timer timer = new Timer("ServerHouseKeepingService", true);
// 工作线程
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";
// sharable handlers
private HandshakeHandler handshakeHandler;
private NettyEncoder encoder;
private NettyConnectManageHandler connectionManageHandler;
private NettyServerHandler serverHandler;
我们主要关心 serverBootStrap 的启动
首先是它的初始化,初始化代码较长,主要做了三件事:
- 初始化 callback 函数执行线程池
- 在 Linux 平台上启用 epoll
- 使用可能存在的 SSL
然后是重头戏,其具体的创建
ServerBootstrap childHandler =
this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
// 半连接队列长度
.option(ChannelOption.SO_BACKLOG, 1024)
// 开启内核中的 net.ipv4.tcp_tw_reuse 选项
.option(ChannelOption.SO_REUSEADDR, true)
// 关闭操作系统的连接维护,由自己去干
.option(ChannelOption.SO_KEEPALIVE, false)
// 禁用 Nagle 算法
.childOption(ChannelOption.TCP_NODELAY, true)
// 设定发送缓冲区和接收缓冲区大小
.childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
.childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())
// 设置监听端口(0.0.0.0:xx)
.localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)