Netty笔记

Netty笔记

起男 29 2025-05-28

Netty笔记

线程模型

Netty 采用多线程 Reactor 模型,核心线程分为两类:

  1. Boss 线程组 (EventLoopGroup)
    • 负责接受客户端连接
    • 将新连接注册到 Worker 线程组
    • 通常只需要1-2个线程
  2. Worker 线程组 (EventLoopGroup)
    • 处理已建立连接的I/O操作
    • 执行用户的 ChannelHandler
    • 线程数通常为 CPU 核心数×2
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();

核心组件

Channel

  • 网络连接的抽象,代表一个打开的连接
  • 不同类型的实现:NIO、OIO、Epoll 等

EventLoop

  • 事件循环,处理 Channel 的I/O事件
  • 一个 EventLoop 可服务多个 Channel
  • 每个 Channel 的生命周期内只绑定一个 EventLoop

ChannelPipeline

  • 处理链,包含一系列 ChannelHandler
  • 入站(Inbound)和出站(Outbound)处理分开

ChannelHandler

  • 实际业务逻辑处理器
  • 常用实现:编解码器、业务处理器等

ChannelFuture

  • 异步操作的结果通知机制
  • 可以添加监听器处理操作完成事件

工作流程

典型 TCP 服务器工作流程:

  1. 初始化两个 EventLoopGroup
  2. 创建 ServerBootstrap 并配置参数
  3. 绑定端口,启动服务
  4. Boss 线程接受连接,分配给 Worker 线程
  5. Worker 线程处理连接的读写事件
  6. 事件在 ChannelPipeline 中流转处理
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
 .channel(NioServerSocketChannel.class)
 .childHandler(new ChannelInitializer<SocketChannel>() {
     @Override
     public void initChannel(SocketChannel ch) {
         ch.pipeline().addLast(new MyHandler());
     }
 });
ChannelFuture f = b.bind(port).sync();

关键设计

零拷贝

Netty 通过以下方式实现高效数据传输:

ByteBuf

  • 自定义的字节容器,支持堆内存和直接内存
  • 引用计数管理,减少内存拷贝
  • 池化技术减少内存分配开销

CompositeByteBuf

  • 合并多个 ByteBuf,逻辑上视为一个整体
  • 避免合并时的内存拷贝

FileRegion

  • 文件传输时使用零拷贝技术
  • 直接通过 DMA 将文件内容发送到网络

内存管理

内存池化

  • 预先分配大块内存,减少频繁分配/释放
  • 通过 Arena 分配策略提高并发性能

引用计数

  • 基于 ReferenceCounted 接口
  • 当引用计数为0时自动释放资源

内存泄漏检测

  • 通过采样方式检测未释放的 ByteBuf
  • 开发阶段可开启严格检测模式

高性能设计

无锁化设计

  • 每个 Channel 绑定固定 EventLoop
  • 单线程处理 Channel 的所有事件
  • 避免多线程竞争

高效序列化

  • 支持 Protobuf、Thrift 等高效编解码
  • 提供 LengthFieldBasedFrameDecoder 解决粘包问题

灵活的线程模型

  • 支持单线程、多线程模型
  • 可配置业务线程池处理耗时操作

核心机制

事件传播机制

事件在 Pipeline 中的流动方向:

  • Inbound 事件:从网络到应用方向
    • 如 channelRead、channelActive 等
    • 依次调用 InboundHandler
  • Outbound 事件:从应用到网络方向
    • 如 write、connect 等
    • 逆序调用 OutboundHandler

责任链模式

ChannelPipeline 采用责任链模式:

  1. 每个 Handler 处理特定功能
  2. 可以动态添加/移除 Handler
  3. 事件依次传递,可中途终止
pipeline.addLast("decoder", new MyDecoder());
pipeline.addLast("encoder", new MyEncoder());
pipeline.addLast("handler", new BusinessHandler());

异步编程模型

基于 Future-Listener 机制:

  1. I/O 操作返回 ChannelFuture
  2. 可以同步等待或异步监听
  3. 通过回调处理操作结果
ChannelFuture future = channel.write(msg);
future.addListener(f -> {
    if (f.isSuccess()) {
        // 操作成功
    } else {
        // 操作失败
    }
});

性能优化

  1. 合理配置线程数
    • BossGroup 通常1个线程足够
    • WorkerGroup 建议2-16个线程
  2. 避免阻塞EventLoop
    • 耗时操作应使用业务线程池
    • 不要在执行器中执行阻塞操作
  3. 合理使用内存
    • 优先使用池化的直接内存
    • 及时释放引用计数对象
  4. 优化Handler设计
    • 共享无状态的Handler
    • 避免在Handler中创建大量临时对象