入站事件和出站事件在一个双向链表中,入站事件会从链表 head 往后传递到最后一个入站的 handler,出站事件会从链表 tail 往前传递到最前一个出站的 handler,两种类型的 handler 互不干扰 。
Netty 工作原理架构
初始化并启动 Netty 服务端过程如下:
publicstaticvoidmain(String[] args) {
// 创建mainReactor
NioEventLoopGroup boosGroup = newNioEventLoopGroup();
// 创建工作线程组
NioEventLoopGroup workerGroup = newNioEventLoopGroup();
final ServerBootstrap serverBootstrap = newServerBootstrap();
serverBootstrap
// 组装NioEventLoopGroup
. group(boosGroup, workerGroup)
// 设置channel类型为NIO类型
.channel(NioServerSocketChannel.class)
// 设置连接配置参数
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
// 配置入站、出站事件handler
.childHandler( newChannelInitializer<NioSocketChannel>() {
@ Override
protectedvoidinitChannel(NioSocketChannel ch) {
// 配置入站、出站事件channel
ch.pipeline().addLast(...);
ch.pipeline().addLast(...);
}
});
// 绑定端口
intport = 8080;
serverBootstrap.bind(port).addListener(future -> {
if(future.isSuccess()) {
System. out.println( newDate() + ": 端口["+ port + "]绑定成功!");
} else{
System.err.println( "端口["+ port + "]绑定失败!");
}
});
}
基本过程如下:
初始化创建 2 个 NioEventLoopGroup,其中 boosGroup 用于 Accetpt 连接建立事件并分发请求,workerGroup 用于处理 I/O 读写事件和业务逻辑 。
基于 ServerBootstrap(服务端启动引导类),配置 EventLoopGroup、Channel 类型,连接参数、配置入站、出站事件 handler 。
绑定端口,开始工作 。
结合上面介绍的 Netty Reactor 模型,介绍服务端 Netty 的工作架构图:
服务端 Netty Reactor 工作架构图

文章插图
Server 端包含 1 个 Boss NioEventLoopGroup 和 1 个 Worker NioEventLoopGroup 。
NioEventLoopGroup 相当于 1 个事件循环组,这个组里包含多个事件循环 NioEventLoop,每个 NioEventLoop 包含 1 个 Selector 和 1 个事件循环线程 。
每个 Boss NioEventLoop 循环执行的任务包含 3 步:
轮询 Accept 事件
处理 Accept I/O 事件,与 Client 建立连接,生成 NioSocketChannel,并将 NioSocketChannel 注册到某个 Worker NioEventLoop 的 Selector 上 。
处理任务队列中的任务,runAllTasks 。任务队列中的任务包括用户调用 eventloop.execute 或 schedule 执行的任务,或者其他线程提交到该 eventloop 的任务 。
每个 Worker NioEventLoop 循环执行的任务包含 3 步:
轮询 Read、Write 事件
处理 I/O 事件,即 Read、Write 事件,在 NioSocketChannel 可读、可写事件发生时进行处理 。
处理任务队列中的任务,runAllTasks 。
其中任务队列中的 Task 有 3 种典型使用场景 。
①用户程序自定义的普通任务
ctx.channel().eventLoop().execute( newRunnable() {
@Override
publicvoidrun(){
//...
}
});
②非当前 Reactor 线程调用 Channel 的各种方法
例如在推送系统的业务线程里面,根据用户的标识,找到对应的 Channel 引用,然后调用 Write 类方法向该用户推送消息,就会进入到这种场景 。最终的 Write 会提交到任务队列中后被异步消费 。
③用户自定义定时任务
ctx.channel().eventLoop().schedule( newRunnable() {
@Override
publicvoidrun(){
}
}, 60, TimeUnit.SECONDS);
总结
现在稳定推荐使用的主流版本还是 Netty4,Netty5 中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显,所以这个版本不推荐使用,官网也没有提供下载链接 。
Netty 入门门槛相对较高,是因为这方面的资料较少,并不是因为它有多难,大家其实都可以像搞透 Spring 一样搞透 Netty 。
【Netty架构原理深度解析,必学框架!】
推荐阅读
- 常用架构模式
- 抖音群控原理是什么?
- 架构:缓存设计
- SSH远程登录原理是什么?
- 路由器与交换机的工作原理
- 浅谈Linux系统中的7种运行级别及其原理
- 3D电影的原理
- 下象棋要掌握的布局原理 怎样下象棋
- 喝生姜红茶减肥好不好 生姜红茶减肥原理和注意事项
- Nacos配置中心集群原理及源码分析
