类图
start
public void start() {
// 初始化DefaultEventExecutorGroup
this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(nettyServerConfig.getServerWorkerThreads(),
new ThreadFactoryImpl("NettyServerCodecThread_"));
// 初始化Sharable的Handler
prepareSharableHandlers();
// 设置ServerBootstrap
serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.SO_KEEPALIVE, false)
.childOption(ChannelOption.TCP_NODELAY, true)
.localAddress(new InetSocketAddress(this.nettyServerConfig.getBindAddress(),
this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
// 向SocketChannel中添加handler
configChannel(ch);
}
});
// 添加自定义配置
addCustomConfig(serverBootstrap);
try {
ChannelFuture sync = serverBootstrap.bind().sync();
InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress();
if (0 == nettyServerConfig.getListenPort()) {
this.nettyServerConfig.setListenPort(addr.getPort());
}
log.info("RemotingServer started, listening {}:{}", this.nettyServerConfig.getBindAddress(),
this.nettyServerConfig.getListenPort());
this.remotingServerTable.put(this.nettyServerConfig.getListenPort(), this);
} catch (Exception e) {
throw new IllegalStateException(String.format("Failed to bind to %s:%d", nettyServerConfig.getBindAddress(),
nettyServerConfig.getListenPort()), e);
}
if (this.channelEventListener != null) {
this.nettyEventExecutor.start();
}
TimerTask timerScanResponseTable = new TimerTask() {
@Override
public void run(Timeout timeout) {
try {
NettyRemotingServer.this.scanResponseTable();
} catch (Throwable e) {
log.error("scanResponseTable exception", e);
} finally {
// 1s 后继续执行
timer.newTimeout(this, 1000, TimeUnit.MILLISECONDS);
}
}
};
// 首次调度3s后执行
this.timer.newTimeout(timerScanResponseTable, 1000 * 3, TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
NettyRemotingServer.this.printRemotingCodeDistribution();
} catch (Throwable e) {
TRAFFIC_LOGGER.error("NettyRemotingServer print remoting code distribution exception", e);
}
}, 1, 1, TimeUnit.SECONDS);
}
有意思的是,这里使用不同方式实现了定时任务。这里简单总结一下二者的区别和适用场景
TimerTask:
基于单线程的时间轮算法,不支持并发,如果一个任务执行时间过长会阻塞后续任务的执行,适用于简单轻量的任务调度
ScheduledExecutorService
使用线程池来调度任务,可以并行多个任务,提供了更多的配置,灵活性扩展性更强,适用于复杂的任务调度(个人认为ScheduledExecutorService完全可以代替TimerTask)
handler
下面展示了NettyRemotingServer启动时向channel中添加的一些handler
/**
* config channel in ChannelInitializer
*
* @param ch the SocketChannel needed to init
* @return the initialized ChannelPipeline, sub class can use it to extent in the future
*/
protected ChannelPipeline configChannel(SocketChannel ch) {
return ch.pipeline()
// 握手Handler,在初始握手过程中检测协议类型,并根据检测结果动态调整ChannelPipeline以添加相应的解码器和处理器
.addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, new HandshakeHandler())
.addLast(defaultEventExecutorGroup,
// 编码器
encoder,
// 解码器
new NettyDecoder(),
// 统计消息的请求码和响应码的分布情况的handler
distributionHandler,
// 心跳检测handler,指定时间内没有读写消息会触发事件,该事件由connectionManageHandler中注册的userEventTriggered方法来监听
new IdleStateHandler(0, 0,
nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
// 连接管理相关handler
connectionManageHandler,
// 核心处理消息的handler
serverHandler
);
}
NettyServerHandler
NettyServerHandler是核心处理消息的handler
@ChannelHandler.Sharable
public class NettyServerHandler extends SimpleChannelInboundHandler<RemotingCommand> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) {
int localPort = RemotingHelper.parseSocketAddressPort(ctx.channel().localAddress());
// 可能存在多个子server,这里根据本地端口获取相关NettyRemotingAbstract实例处理(是5.0的新特性,和BrokerContainer相关)
NettyRemotingAbstract remotingAbstract = NettyRemotingServer.this.remotingServerTable.get(localPort);
if (localPort != -1 && remotingAbstract != null) {
// 处理消息
remotingAbstract.processMessageReceived(ctx, msg);
return;
}
// The related remoting server has been shutdown, so close the connected channel
RemotingHelper.closeChannel(ctx.channel());
}
/**
* channel可写状态发生变化时,自动启用或禁用通道的自动读取功能
* @param ctx
* @throws Exception
*/
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
if (channel.isWritable()) {
if (!channel.config().isAutoRead()) {
channel.config().setAutoRead(true);
log.info("Channel[{}] turns writable, bytes to buffer before changing channel to un-writable: {}",
RemotingHelper.parseChannelRemoteAddr(channel), channel.bytesBeforeUnwritable());
}
} else {
channel.config().setAutoRead(false);
log.warn("Channel[{}] auto-read is disabled, bytes to drain before it turns writable: {}",
RemotingHelper.parseChannelRemoteAddr(channel), channel.bytesBeforeWritable());
}
super.channelWritabilityChanged(ctx);
}
}
而NettyRemotingAbstract#processMessageReceived
在NettyRemotingClient这篇笔记中已经介绍过了