Netty 4.1.x 是最稳主线,生产优先用 netty-all;需显式指定 version;JDK 8+,Epoll 需 Linux 环境;boss/worker Group 要分离;pipeline 入站顺序须为 ByteToMessageDecoder→SimpleChannelInboundHandler;“Failed to create a selector” 多因文件描述符超限。

怎么选 Netty 版本和 Maven 依赖
Netty 4.1.x 是当前最稳的主线,别碰 5.0(已废弃)或太老的 4.0.x。生产环境优先用 io.netty:netty-all,省得自己凑一堆模块;但如果你只做 HTTP 服务,netty-handler + netty-transport 就够了,能减小 jar 包体积。
- 用 Maven 写依赖时,必须显式指定
version,别依赖父 POM 的隐式版本——不同 Netty 小版本之间ChannelOption默认值可能变 - JDK 版本要对齐:
netty-all:4.1.100.Final要求 JDK 8+,但若用了EpollEventLoopGroup,就得 JDK 8 + Linux + glibc 支持 -
netty-tcnative是可选项,不加也能跑,但加了才能启用 OpenSSL 和 epoll —— 别在 Windows 上强行配它,会报java.lang.UnsatisfiedLinkError: no netty_tcnative in java.library.path
启动类里 EventLoopGroup 怎么配才不翻车
EventLoopGroup 不是随便 new 两个就完事的。服务端必须分 bossGroup(只管 accept)和 workerGroup(真干活),且两者不能是同一个实例。
-
bossGroup线程数设 1 就够了,多设反而增加上下文切换开销;workerGroup推荐设为Runtime.getRuntime().availableProcessors() * 2 - 别在
channelActive()里直接写业务逻辑,容易阻塞 event loop;要用ctx.executor().submit()或ctx.channel().eventLoop().submit()搬到别的线程 - shutdown 一定要调
group.shutdownGracefully(),否则 JVM 退出时线程没回收,进程残留
为什么 ChannelPipeline.addLast() 顺序一错就收不到数据
Netty 的 pipeline 是责任链,入站(inbound)和出站(outbound)处理器执行方向相反,顺序错了,解码器可能根本没机会处理字节流。
- 入站顺序必须是:
ByteToMessageDecoder→SimpleChannelInboundHandler,反了就会抛ClassCastException,因为 handler 拿到的是原始ByteBuf而不是解码后的对象 - 如果用了
HttpServerCodec,它内部已经集成了HttpRequestDecoder和HttpResponseEncoder,别再额外加StringEncoder,否则响应体被 double 编码 - 自定义
ChannelHandler如果重写了handlerAdded(),记得调super.handlerAdded(ctx),否则某些内置 handler(比如IdleStateHandler)会失效
运行时报 “Failed to create a selector” 怎么快速定位
这错误本质是 JVM 打开的文件描述符超限,常见于 Linux 环境下未调优,不是 Netty 代码写错了。
立即学习“Java免费学习笔记(深入)”;
- 先查系统限制:
ulimit -n,默认常是 1024,而一个EventLoopGroup线程至少占 1 个 selector,每个连接还占 1 个 fd - Java 启动参数加上
-Dio.netty.selectorAutoRebuildThreshold=512,避免单个 selector 过载后崩溃(Netty 4.1.60+ 默认开启,但老版本得手动开) - 如果用 Docker,别忘了配
--ulimit nofile=65536:65536,容器里ulimit不继承宿主机
Netty 启动看似简单,但线程模型、pipeline 顺序、资源释放这三块最容易漏掉细节——尤其是本地调试时一切正常,上生产后连接数一上去就崩,问题往往藏在 shutdownGracefully() 是否被调用、ByteBuf 是否被正确 release() 这些地方。











