Netty 工作原理架构
初始化并启动 Netty 服务端过程如下:
public static void main(String[] args) {
// 创建mainReactor
NioEventLoopGroup boosGroup = new NioEventLoopGroup();
// 创建工作线程组
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
final ServerBootstrap serverBootstrap = new ServerBootstrap();
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(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) {
// 配置入站、出站事件channel
ch.pipeline().addLast(...);
ch.pipeline().addLast(...);
}
});
// 绑定端口
int port = 8080;
serverBootstrap.bind(port).addListener(future -> {
if (future.isSuccess()) {
System.out.println(new Date() + ": 端口[" + port + "]绑定成功!");
} else {
System.err.println("端口[" + port + "]绑定失败!");
}
});
}
基本过程如下:
初始化创建 2 个 NioEventLoopGroup,其中 boosGroup 用于 Accetpt 连接建立事件并分发请求,workerGroup 用于处理 I/O 读写事件和业务逻辑。
基于 ServerBootstrap(服务端启动引导类),配置 EventLoopGroup、Channel 类型,连接参数、配置入站、出站事件 handler。
绑定端口,开始工作。
结合上面介绍的 Netty Reactor 模型,介绍服务端 Netty 的工作架构图:
这可能是目前最透彻的Netty原理架构解析
服务端 Netty Reactor 工作架构图
Server 端包含 1 个 Boss NioEventLoopGroup 和 1 个 Worker NioEventLoopGroup。
NioEventLoopGroup 相当于 1 个事件循环组,这个组里包含多个事件循环 NioEventLoop,每个 NioEventLoop 包含 1 个 Selector 和 1 个事件循环线程。只要一步一个脚印,水滴石穿,吃透、搞懂、拿捏住是完全没有问题的!看到这里的都是妥妥的铁粉无疑了,底下是我微信找到我的可是有大把源码,学习路线思维导图啥的,多的我就不透露1253431195看大家自己的积极性了啊,热爱所热爱的,学习伴随终生
每个 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(new Runnable() {
@Override
public void run() {
//...
}
});
②非当前 Reactor 线程调用 Channel 的各种方法
例如在推送系统的业务线程里面,根据用户的标识,找到对应的 Channel 引用,然后调用 Write 类方法向该用户推送消息,就会进入到这种场景。最终的 Write 会提交到任务队列中后被异步消费。
③用户自定义定时任务
ctx.channel().eventLoop().schedule(new Runnable() {
@Override
public void run() {
}
}, 60, TimeUnit.SECONDS);
总结
现在稳定推荐使用的主流版本还是 Netty4,Netty5 中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显,所以这个版本不推荐使用,官网也没有提供下载链接。
Netty 入门门槛相对较高,是因为这方面的资料较少,并不是因为它有多难,大家其实都可以像搞透 Spring 一样搞透 Netty。
在学习之前,建议先理解透整个框架原理结构,运行过程,可以少走很多弯路。
参考资料:
Netty入门与实战:仿写微信 IM 即时通讯系统
Netty官网
Netty 4.x学习笔记 - 线程模型
Netty入门与实战
理解高性能网络模型
Netty基本原理介绍
software-architecture-patterns.pdf
Netty高性能之道 —— 李林锋
《Netty In Action》
《Netty权威指南》
JAVA核心面试题库
链接:https://pan.baidu.com/s/1SaN9ytv7DBj2JuQWC5VBxg
提取码:132k