Skip to content

Netty ​

Netty 是高性能网络通信框架,常用于长连接、实时推送、聊天和网关场景。

推荐阅读顺序:

  1. 从零到生产级掌握
  2. 从零到精通验收清单
  3. 商业场景训练营
  4. 基础
  5. Reactor模型
  6. EventLoop
  7. ByteBuf
  8. ChannelPipeline
  9. 编解码
  10. 粘包拆包
  11. 实战入门
  12. 面试题

如果你想检查自己是否真的从零基础学懂到能面试、能落地、能排查,按 Netty 从零到精通验收清单 逐项验收。它会把 BIO/NIO、Reactor、EventLoop、Pipeline、ByteBuf、编解码、粘包半包、心跳、背压和生产排查串起来。

为什么需要 Netty ​

Netty 是基于 NIO 的网络通信框架,它封装了 Selector、Channel、Buffer、线程模型和编解码流程,让开发者更容易构建高性能网络应用。

如果直接使用 JDK NIO,需要自己处理很多细节:什么时候注册读事件,什么时候取消写事件,半包数据放在哪里,连接关闭时怎么释放资源,业务处理阻塞了 Selector 线程怎么办。初学者容易把代码写成“能跑但不稳定”,连接一多就出现 CPU 空转、内存泄漏、消息错乱和连接假死。

Netty 的价值是把这些低层细节整理成稳定的模型:

  1. 用 EventLoop 统一处理 IO 事件和任务。
  2. 用 ChannelPipeline 把解码、业务、编码拆成责任链。
  3. 用 ByteBuf 解决网络字节读写和内存管理问题。
  4. 用内置编解码器解决粘包、拆包、协议边界问题。
  5. 用启动器和配置项隐藏 NIO 注册、绑定、监听的复杂流程。

Netty 适合什么场景 ​

常见场景:

  1. IM 聊天、站内消息、实时推送。
  2. RPC 框架底层通信。
  3. 网关、代理、长连接服务。
  4. 自定义 TCP/UDP 协议。
  5. 大量连接、低延迟网络交互。

普通 HTTP CRUD 系统不一定需要直接使用 Netty,Spring MVC 或 Spring WebFlux 已经足够。Netty 更适合需要掌控网络协议和连接生命周期的场景。

Netty 请求处理流程 ​

mermaid
flowchart TD
    A["客户端连接"] --> B["BossGroup 接收连接"]
    B --> C["注册到 WorkerGroup"]
    C --> D["ChannelPipeline 处理链"]
    D --> E["Decoder 解码字节"]
    E --> F["业务 Handler 处理消息"]
    F --> G["Encoder 编码响应"]
    G --> H["写回客户端"]

这张图要按两个边界理解:

边界说明如果分不清会怎样
连接接入边界BossGroup 只负责接收新连接,把连接交给 WorkerGroup把耗时逻辑放到 BossGroup 会影响新连接接入
消息处理边界WorkerGroup 触发 Pipeline,Pipeline 再逐层处理消息把解码、鉴权、业务、编码混在一个 Handler 中,后期很难排查和复用

核心原理一眼看懂 ​

Netty 的本质不是“更多线程”,而是“少量线程监听大量连接的事件”。一个连接没有数据时不占用一个业务线程,有数据可读、可写或关闭时才触发事件。

mermaid
flowchart TD
    A["操作系统监听 Socket 状态"] --> B["Selector 发现就绪事件"]
    B --> C["EventLoop 取出事件"]
    C --> D["找到对应 Channel"]
    D --> E["触发 ChannelPipeline"]
    E --> F["Handler 顺序处理"]
    F --> G["必要时写回响应"]

为什么这样能支撑高并发:

  1. 连接空闲时不会占住一个线程。
  2. IO 事件由固定数量的 EventLoop 轮询处理,减少线程创建和切换。
  3. 同一个 Channel 通常固定在同一个 EventLoop 上,减少并发锁竞争。
  4. 复杂业务可以投递到业务线程池,避免阻塞 IO 线程。

核心组件 ​

组件作用初学者必须知道的点
EventLoopGroup线程组,负责处理连接和 IO 事件不要在 EventLoop 中执行慢 SQL、同步 HTTP、大文件计算
Channel网络连接抽象一个客户端连接通常对应一个 Channel
ChannelPipeline处理器链入站处理请求,出站处理响应,顺序很重要
ChannelHandler编解码、业务处理、异常处理Handler 是否可共享要看是否有状态
ByteBufNetty 的高性能字节缓冲区读写指针和引用计数是排查内存问题的关键
Bootstrap客户端启动器客户端连接远端服务用它
ServerBootstrap服务端启动器服务端绑定端口、接收连接用它

学习重点 ​

  1. Reactor 线程模型:理解 Boss 和 Worker 分工。
  2. ByteBuf:理解读写指针、引用计数、内存泄漏。
  3. 编解码:处理 TCP 粘包半包问题。
  4. Pipeline:掌握入站、出站处理器的执行顺序。
  5. 心跳和重连:保障长连接稳定性。
  6. 背压和限流:避免写入过快导致内存堆积。

排查方向 ​

问题排查方向
连接数上不去检查系统文件句柄、线程模型、端口和 backlog
内存持续增长检查 ByteBuf 是否释放、是否有写队列堆积
消息解析错乱检查协议边界、长度字段、粘包半包处理
延迟升高检查 EventLoop 是否被阻塞、业务是否异步化

如果不用或用错 Netty 会怎样 ​

场景可能后果正确思路
用 BIO 做大量长连接线程数量暴涨,内存和上下文切换成本很高使用 NIO/Reactor 模型
在 EventLoop 里查数据库一个慢查询拖慢同 EventLoop 上的多个连接投递到业务线程池,完成后切回 EventLoop 写响应
没有处理粘包半包消息解析错乱,偶发出现“多一段/少一段”数据使用长度字段、分隔符或固定长度协议
忘记释放 ByteBuf堆外内存持续增长,最终 OOM明确消息所有权,使用 release 或自动释放 Handler
Pipeline 顺序错误编码器、解码器、鉴权器不生效按“拆包 -> 解码 -> 鉴权 -> 业务 -> 编码”组织

代码 Demo:最小 Netty 服务端 ​

下面是一个最小 TCP 服务端,收到客户端消息后回写 ok。

java
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();

try {
    ServerBootstrap bootstrap = new ServerBootstrap();
    bootstrap.group(boss, worker)
        .channel(NioServerSocketChannel.class)
        .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel channel) {
                channel.pipeline()
                    .addLast(new StringDecoder())
                    .addLast(new StringEncoder())
                    .addLast(new SimpleChannelInboundHandler<String>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                            System.out.println("收到消息:" + msg);
                            ctx.writeAndFlush("ok\n");
                        }
                    });
            }
        });

    ChannelFuture future = bootstrap.bind(9000).sync();
    future.channel().closeFuture().sync();
} finally {
    boss.shutdownGracefully();
    worker.shutdownGracefully();
}

这个 Demo 对应前面的流程:Boss 接收连接,Worker 处理 IO,Pipeline 负责解码、业务处理和编码。