Netty 学起来容易散:NIO、Selector、Channel、EventLoop、Pipeline、Bootstrap、ByteBuf,每个名词都能展开很多。我的习惯是先把它压成三条主线:IO 模型、线程模型和数据处理模型。
IO 模型回答“连接和读写怎么被监听”;线程模型回答“谁负责接连接,谁负责读写”;数据处理模型回答“收到字节以后怎么一步步变成业务对象”。
Reactor 模型先看角色
Netty 服务端常见结构是两个线程组:
- BossGroup:负责接收客户端连接。
- WorkerGroup:负责已建立连接上的读写事件。
服务启动后,BossGroup 里的 NioEventLoop 监听服务端端口。当有客户端连接进来,它接收连接并生成客户端 Channel,然后把这个 Channel 注册到 WorkerGroup 里的某个 NioEventLoop 上。
从这个时刻开始,这个客户端连接的读写事件主要由 WorkerGroup 处理。BossGroup 不再继续处理这个连接上的业务数据。
这就是最基础的分工:Boss 接客,Worker 干活。
EventLoop 是线程和 Selector 的组合
EventLoop 可以理解成一个长期运行的事件循环。它通常绑定一个线程,里面维护一个 Selector,不断做几件事:
- 等待 IO 事件。
- 处理注册到它上面的 Channel。
- 执行普通任务。
- 执行定时任务。
一个 Channel 注册到某个 EventLoop 后,后续事件一般就在这个 EventLoop 里处理。这种绑定关系让 Netty 避免了大量锁竞争,也让 ChannelHandler 的执行顺序更容易推理。
这里有个容易忽略的点:BossGroup 自己也有任务队列和定时任务。它接收到的任务不会自动交给 WorkerGroup,除非代码显式安排。两个线程组职责不同,但都是 EventLoop 模型。
Bootstrap 和 Channel 是两个操作入口
写 Netty 代码时经常看到两个对象:
ServerBootstrap:服务端启动辅助类,用来配置线程组、Channel 类型、端口和 Handler。Channel:连接抽象,代表服务端监听通道或客户端连接通道。
ServerBootstrap 更像启动配置器。真正运行后,网络事件都会落到 Channel 和它背后的 EventLoop、Pipeline 上。
服务端大概会配置:
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new YourDecoder());
ch.pipeline().addLast(new YourBusinessHandler());
}
});
这里 childHandler 配的是客户端连接 Channel 的处理链,不是服务端监听 Channel 的处理链。
Pipeline 负责数据流转
如果 EventLoop 解决“谁来处理”,Pipeline 解决“怎么处理”。
一个 Channel 会有一个 ChannelPipeline,里面串着多个 ChannelHandler。数据从网络进来后,会按入站方向经过 decoder、校验、业务处理等 handler;数据写出去时,会按出站方向经过 encoder、压缩、写出等 handler。
常见链路可以这样分:
- ByteToMessageDecoder:把字节流拆成消息。
- MessageToByteEncoder:把消息编码成字节。
- SimpleChannelInboundHandler:处理业务对象。
- ExceptionHandler:统一处理异常和关闭连接。
Pipeline 的好处是把网络协议处理拆成多个可组合步骤。不要把解码、鉴权、业务、写响应全塞进一个 Handler,否则后面很难维护。
Netty 和 Java NIO 的关系
Netty 不是绕开 Java NIO,而是在 NIO 之上封装了一套更容易使用的网络框架。底层仍然离不开 Selector、Channel、SelectionKey 这些概念。
Java NIO 直接写会遇到很多重复问题:半包粘包、注册事件、线程模型、缓冲区管理、异常关闭、连接生命周期。Netty 把这些常见问题做成框架层能力,业务侧重点就能放在协议和处理逻辑上。
学习 Netty 时,最好至少理解 Java NIO 的三件事:
- Selector 可以监听多个 Channel。
- Channel 可以注册读、写、连接、接收事件。
- 事件触发后需要业务线程处理对应逻辑。
理解这三点,再看 EventLoop 就会顺很多。
排查 Netty 问题看什么
Netty 问题常见在几层:
- 连接层:端口是否监听,连接是否建立。
- 线程层:Boss/Worker 是否被阻塞,业务是否跑在 IO 线程里太久。
- 协议层:半包、粘包、编码解码是否一致。
- 内存层:ByteBuf 是否释放,是否有泄漏。
- 业务层:Handler 顺序是否正确,异常是否被吞掉。
最容易犯的错是把阻塞业务逻辑放在 EventLoop 里。EventLoop 一旦被慢 SQL、远程 HTTP、文件 IO 阻塞,挂在这个 EventLoop 上的多个 Channel 都会被拖慢。
最后抓住三个关键词
Netty 可以先按三个关键词记:
- EventLoop:事件循环和线程边界。
- Channel:连接和 IO 操作抽象。
- Pipeline:协议和业务处理链。
BossGroup 接连接,WorkerGroup 管读写,Pipeline 处理数据。把这条线理清,后面再学 ByteBuf、编解码、自定义协议和性能调优,就有了骨架。



