← 返回首页
一、NIO 基础回顾
- BIO 问题:一个连接一个线程,阻塞等待,高并发下线程资源耗尽
- NIO 三大组件:Channel(双向通道)、Buffer(缓冲区,读写数据的中介)、Selector(多路复用器,一个线程监听多个 Channel)
- Selector 工作原理:注册感兴趣的事件(ACCEPT/READ/WRITE)→ select() 阻塞等待 → 遍历就绪的 SelectionKey 处理
- 原生 NIO 痛点:API 复杂、Epoll Bug(空轮询导致 CPU 100%)、粘包拆包需自行处理、没有现成的编解码器
二、Netty 线程模型
- Reactor 模式:事件驱动,将 IO 事件分发给对应的 Handler 处理
- 单 Reactor 单线程:一个线程处理所有事件,简单但无法利用多核
- 单 Reactor 多线程:Reactor 线程负责 IO,业务交给线程池
- 主从 Reactor(Netty 采用):BossGroup 接收连接 → WorkerGroup 处理 IO 读写 → 业务线程池处理耗时逻辑
- EventLoopGroup:线程组,BossGroup 通常 1 个线程,WorkerGroup 默认 CPU 核数×2
- EventLoop:绑定一个线程,负责处理注册到其上的所有 Channel 的 IO 事件,保证线程安全
三、核心组件
- Channel:网络连接的抽象,NioServerSocketChannel(服务端)/ NioSocketChannel(客户端)
- ChannelPipeline:Handler 链,入站事件从 Head → Tail,出站事件从 Tail → Head
- ChannelHandler:业务处理核心,ChannelInboundHandler(入站,读数据)/ ChannelOutboundHandler(出站,写数据)
- ChannelHandlerContext:Handler 与 Pipeline 的桥梁,可触发下一个 Handler
- ByteBuf:替代 NIO ByteBuffer,读写双指针(readerIndex/writerIndex),支持池化和零拷贝
- Bootstrap:启动引导类,ServerBootstrap(服务端)/ Bootstrap(客户端),链式配置
四、编解码与粘包拆包
粘包拆包原因
- TCP 是流式协议,无消息边界,发送方 Nagle 算法合并小包,接收方缓冲区堆积
Netty 内置解决方案
- FixedLengthFrameDecoder:固定长度拆包
- LineBasedFrameDecoder:换行符分隔
- DelimiterBasedFrameDecoder:自定义分隔符
- LengthFieldBasedFrameDecoder:长度字段拆包(最常用),通过消息头中的长度字段确定消息边界
常用编解码器
- StringEncoder / StringDecoder:字符串编解码
- ObjectEncoder / ObjectDecoder:Java 序列化(不推荐,性能差)
- ProtobufEncoder / ProtobufDecoder:Protobuf 高性能序列化
- 自定义协议:魔数 + 版本 + 序列化方式 + 消息类型 + 长度 + 数据体
五、高性能设计
- 零拷贝:CompositeByteBuf(逻辑合并)/ slice(逻辑拆分)/ FileRegion(transferTo 系统调用)
- 内存池化:PooledByteBufAllocator,jemalloc 算法管理内存,减少 GC 压力
- 无锁串行化:每个 Channel 绑定一个 EventLoop,同一 Channel 的事件在同一线程处理,避免锁竞争
- 高效并发数据结构:mpsc 队列(多生产者单消费者),减少锁开销
- Epoll 空轮询修复:检测到空轮询次数超阈值(默认 512)后重建 Selector
六、实战要点
- 心跳检测:
IdleStateHandler 检测读/写空闲,超时触发事件,配合自定义 Handler 发送心跳包或断开连接
- 断线重连:监听 channelInactive 事件,延迟重连(指数退避)
- 流量整形:
GlobalTrafficShapingHandler 全局限流,控制读写速率
- 内存泄漏检测:
-Dio.netty.leakDetection.level=PARANOID,排查 ByteBuf 未释放
- 应用场景:RPC 框架(Dubbo)、消息中间件(RocketMQ)、即时通讯、游戏服务器、API 网关