Netty 性能调优
概述
Netty 是游戏服务器的通信底座,它的性能上限决定了单机支撑能力。调优集中在三块:EventLoop 线程数(少而精)、内存池(减少 GC 与拷贝)、TCP 参数(吞吐与延迟的平衡)。本文给出 Netty 性能调优的完整清单。
一、EventLoop 线程数规划
1.1 线程模型回顾
EventLoop 分工:
boss 线程:accept 新连接(通常 1 个)
worker 线程:IO 读写 + ChannelHandler 处理
线程数建议:
boss:1(高并发建连可 1-2)
worker:CPU 核数 × 2(常规)
业务线程池:独立规划(见消息分发章节)// 线程数配置
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup(cpuCount * 2);
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker);1.2 线程数误区
误区一:线程越多越好
EventLoop 是 IO 密集,线程数 = 核数附近即可
过多线程 → 上下文切换开销
误区二:业务逻辑放 EventLoop
耗时业务阻塞 EventLoop → 拖垮所有连接
对策:业务操作切独立线程池(见消息分发)
线程监控:
EventLoop 任务积压 → 处理不过来的信号
用 ioRatio 控制 IO/任务时间占比// 将耗时操作移出 EventLoop
pipeline.addLast(DefaultEventExecutorGroup(16), new BizHandler());二、内存池 PooledByteBufAllocator
2.1 内存池价值
ByteBuf 分配问题:
每次读写都分配堆内存 → GC 压力大
系统调用拷贝 → 性能损耗
内存池(Pooled):
复用内存块(避免频繁分配/释放)
减少 GC
减少内存拷贝(零拷贝)
// 启用内存池(默认开启)
b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);2.2 零拷贝
零拷贝途径:
组合 buffer(CompositeByteBuf):多个 buffer 组合不拷贝
直接内存(DirectBuffer):IO 直接读写堆外
FileRegion:文件直接发送
使用注意:
直接内存不归 JVM 堆管 → 需手动释放/池化
RefCnt 引用计数管理(避免泄漏)// 直接内存分配(池化)
ByteBuf buf = allocator.directBuffer(capacity);
// 使用完释放(引用计数归零)
ReferenceCountUtil.release(buf);2.3 泄漏检测
内存泄漏排查:
开启泄漏检测(生产建议 PARANOID 或 SIMPLE 抽样)
leak: netty.bytebuf.leak-detector.level
实践:
自写编解码器注意 release
使用 ByteBufUtil 工具
压测时开启严格检测三、TCP 参数调优
3.1 关键参数
TCP 参数(childOption):
SO_BACKLOG:accept 队列长度(高并发建连调大)
SO_SNDBUF/SO_RCVBUF:读写缓冲(默认即可,不宜过大)
TCP_NODELAY:禁用 Nagle 算法(低延迟,游戏必须开)
SO_KEEPALIVE:TCP 保活(配合应用心跳)
SO_REUSEADDR:端口复用(重启快速)// 游戏服务器推荐配置
b.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.SO_REUSEADDR, true);参数选择逻辑:
TCP_NODELAY 必开(游戏实时性要求)
SO_BACKLOG 视建连峰值(开服瞬间)
缓冲不用盲目调大(默认已优化)3.2 系统层参数
OS 层优化(参考):
net.core.somaxconn:accept 队列上限(配合 SO_BACKLOG)
net.ipv4.tcp_fastopen:快速打开(减少握手延迟)
ulimit 文件句柄:连接数上限
网卡多队列(RSS):多核中断分摊四、协议与业务优化
4.1 编解码优化
编解码性能:
复用解码器实例(无状态 Handler 共享)
避免每消息新建对象(对象池/复用)
二进制协议优于文本(见协议优化章节)
消息体压缩(见协议优化章节)4.2 写优化
写操作优化:
writeAndFlush 批量(多条消息合并 flush)
关闭自动读取策略(半包/背压控制)
大流量场景关注写缓冲积压
// 批量写(减少系统调用)
Channel ch = ...;
ch.write(msg1);
ch.write(msg2);
ch.flush(); // 统一 flush五、性能排查路径
排查流程:
1. 压测(见压测章节)找瓶颈
2. 看 EventLoop 线程占用(profiler)
3. 查 GC 频率与内存分配
4. 查网络(延迟/重传/连接数)
5. 针对性优化后复测对比
监控指标:
连接数、QPS、RT
EventLoop 积压、队列深度
内存(堆 + 直接内存)
丢包/重传六、实现要点
调优清单:
EventLoop = 核数 × 2(业务移出 IO 线程)
内存池开启(PooledByteBufAllocator)
零拷贝(CompositeByteBuf/DirectBuffer)
泄漏检测开启
TCP_NODELAY 必开 + SO_BACKLOG 调大
批量写减少 flush 次数
压测验证效果
常见坑:
业务阻塞 EventLoop → 全连接卡顿
直接内存泄漏 → 引用计数管理
buffer 未 release → 内存增长
盲目调线程数/缓冲 → 反效果与其他系统衔接:
线程模型 → 并发挑战章节
业务线程池 → 消息分发章节
协议压缩 → 协议优化章节
压测 → 压力测试章节