为什么 Netty 适合做网络编程?
结论先行:Netty 把 Java NIO 的复杂度封装成“事件驱动 + 责任链”的编程模型:不用自己写 Selector 循环,不用处理半包与断线重连,粘包、心跳、背压、内存池都是现成的。Dubbo、RocketMQ、Elasticsearch、Cassandra 的通信层都建立在它之上,这本身就是最强的背书。
一、原生 NIO 的四个痛点
| 痛点 | 具体表现 |
|---|
| API 繁琐 | Selector 循环、interestOps、半关闭状态机都要自己写 |
| 半包处理 | read() 一次读到的可能不是一条完整消息,需要自己拼 |
| 已知缺陷 | epoll 空轮询导致 CPU 100%,JDK 层面长期存在 |
| 资源管理 | 缓冲区复用、堆外内存释放、连接泄漏都要手动兜底 |
这四条在业务代码里重复实现一遍,等于重写半个 Netty。
二、Netty 提供的抽象
Bootstrap / ServerBootstrap 启动与参数装配
│
Channel ── EventLoop ── Pipeline ── Handler
│ │ │
│ │ └── 编解码、心跳、业务处理按序串成链
│ └── 一个 Channel 绑定一个线程,串行无锁
└── 统一的读写 API,屏蔽 NIO/EPOLL/KQueue 差异
| 能力 | 对应组件 |
|---|
| 粘包拆包 | LengthFieldBasedFrameDecoder、DelimiterBasedFrameDecoder |
| 心跳检测 | IdleStateHandler |
| 编解码 | MessageToByteEncoder、ByteToMessageDecoder |
| 背压 | isWritable() + 高低水位线 |
| 内存管理 | ByteBufAllocator + 引用计数 + 对象池 |
| 协议扩展 | 自定义 ChannelHandler 插拔 |
三、最小可运行服务端
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new IdleStateHandler(60, 0, 0))
.addLast(new LengthFieldBasedFrameDecoder(65535, 0, 4, 0, 4))
.addLast(new StringDecoder(StandardCharsets.UTF_8))
.addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
ctx.writeAndFlush("echo:" + msg);
}
});
}
});
b.bind(8080).sync().channel().closeFuture().sync();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
四、选型对照
| 方案 | 开发成本 | 性能 | 生态 |
|---|
| 原生 NIO | 高 | 高(但要自己调优) | 无 |
| Netty | 中 | 高 | 极好,主流中间件都在用 |
| Spring WebFlux | 低 | 中高 | Web 场景友好 |
| Mina | 中 | 中 | 社区活跃度下降 |
常见追问
- 追问:Netty 学习曲线高吗?入门低(Bootstrap + Handler 就能跑),精通难(内存池、线程模型、引用计数泄漏排查)。
- 追问:Netty 4 和 5 的差别?Netty 5 已废弃,主线是 4.x;4.1 与 4.2 在 API 与内存分配上有差异,新项目用 4.1 稳定版。
- 追问:能用在 HTTP 服务端吗?可以,
HttpServerCodec 一套就能写 HTTP 服务,但普通 Web 业务用 Spring MVC 更省事,Netty 更适合自定义协议与网关。
小结
- Netty 的价值是把 NIO 的复杂度收进框架,业务只写 Handler。
- 粘包、心跳、背压、内存池都是开箱能力,不用重复造轮子。
- 主从 Reactor + Channel 绑定 EventLoop,是它高性能与线程安全的基础。
- 主流中间件的通信层都基于它,兼容性与踩坑资料充足。