Netty 是 Java 高併發網絡編程的事實標準,廣泛應用於 RPC 框架、消息隊列、網關、IM 系統。本文深度解析 Netty 核心架構:Reactor 線程模型、ChannelPipeline 責任鏈、零拷貝 ByteBuf、內存池、編解碼體系,並提供生產級最佳實踐配置。
| 維度 | 特性 |
|---|---|
| 定位 | 異步事件驅動 NIO 框架,支援 TCP/UDP/HTTP/WebSocket/文件傳輸 |
| IO 模型 | 全異步非阻塞,Future-Listener 機制獲取結果 |
| 性能 | 高吞吐、低延遲、少內存拷貝、對象池復用 |
| 安全 | 完整 SSL/TLS/STARTTLS,Applet/Android 受限環境兼容 |
| 健壯 | 防 OOM、防慢連接攻擊、NIO 空輪詢 Bug 修復 |
| 易用 | 統一 API 屏蔽協議差異、豐富編解碼器、完善文檔 |
EventLoopGroup boss = new NioEventLoopGroup(1); // 接受連接
EventLoopGroup worker = new NioEventLoopGroup(); // IO 處理
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new MyHandler());
}
});
b.bind(8080).sync();
缺點:單線程處理所有 IO,多核 CPU 利用率低。
accept 新連接極高並發連接建立場景(如百萬長連接網關),多 Boss 線程分攤 accept 壓力。
Channel:網絡連接抽象,非阻塞、可註冊到 EventLoopChannelPipeline:雙向鏈表,持有 ChannelHandlerContext 節點| 類型 | 接口 | 典型職責 |
|---|---|---|
| 入站 | ChannelInboundHandlerAdapter | 讀取、解碼、業務邏輯、異常處理 |
| 出站 | ChannelOutboundHandlerAdapter | 寫入、編碼、刷新、關閉 |
| 雙向 | ChannelDuplexHandler | 同時處理入站/出站(如流量整形) |
EventLoop:單線程無限循環 select → process tasks → run tasksEventLoopGroup:線程池,實現 Iterable<EventLoop> 支援輪詢分配| 類型 | 分配區域 | 特點 | 適用場景 |
|---|---|---|---|
| Heap Buffer | JVM 堆 | GC 管理、易用、需堆外拷貝寫入 Socket | 簡單業務、原型開發 |
| Direct Buffer | 堆外內存 | 零拷貝寫入 Socket、手動管理、分配較慢 | 高性能網絡傳輸 |
| Pooled Buffer | 堆/堆外 | Buddy 算法內存池、減少 GC、復用對象 | 生產環境默認推薦 |
// 讀寫指針分離,無需 flip()
ByteBuf buf = Unpooled.buffer(1024);
buf.writeBytes(data); // writerIndex 遞增
buf.readBytes(dst); // readerIndex 遞增
int readable = buf.readableBytes(); // writerIndex - readerIndex
// 引用計數(Pooled 必須釋放)
buf.retain(); // +1
buf.release(); // -1, 歸零時回收內存
-Dio.netty.allocator.type=pooled # 啟用池化(4.1+ 默認開啟)
-Dio.netty.allocator.numHeapArenas=16
-Dio.netty.allocator.numDirectArenas=16
-Dio.netty.allocator.pageSize=8192
-Dio.netty.allocator.maxOrder=11 // 最大 4MB chunk
MessageToByteEncoder:自定義編解碼基類// HTTP 服務器
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536)); // 聚合 FullHttpRequest
pipeline.addLast(new MyHttpHandler());
// WebSocket
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new MyWebSocketHandler());
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024*1024, 0, 4, 0, 4));
pipeline.addLast(new ProtobufDecoder(MyMessage.getDefaultInstance()));
pipeline.addLast(new ProtobufEncoder());
pipeline.addLast(new MyBusinessHandler());
// FileRegion 實現零拷貝(sendFile 系統調用)
FileChannel fc = new FileInputStream(file).getChannel();
FileRegion region = new DefaultFileRegion(fc, 0, file.length());
ctx.writeAndFlush(region).addListener(ChannelFutureListener.CLOSE);
優勢:內核態直接 DMA 磁盤→網卡,避免用戶態拷貝,CPU 佔用極低。
SslContext sslCtx = SslContextBuilder.forServer(keyManagerFactory)
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
.build();
pipeline.addFirst(sslCtx.newHandler(ch.alloc())); // 必須在 First 位置
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024) // 連接隊列
.option(ChannelOption.SO_REUSEADDR, true) // 端口復用
.childOption(ChannelOption.TCP_NODELAY, true) // 禁用 Nagle
.childOption(ChannelOption.SO_KEEPALIVE, true) // 心跳
.childOption(ChannelOption.SO_RCVBUF, 64*1024) // 接收緩衝
.childOption(ChannelOption.SO_SNDBUF, 64*1024) // 發送緩衝
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
// 空閒檢測
p.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));
// 解碼
p.addLast(new LengthFieldBasedFrameDecoder(1024*1024, 0, 4, 0, 4));
p.addLast(new MyDecoder());
// 業務
p.addLast(new MyBusinessHandler());
// 編碼
p.addLast(new MyEncoder());
}
});
// 優雅關閉
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}));
ctx.executor().execute(() -> { ... })release(),啟用 -Dio.netty.leakDetection.level=paranoidSelectorUtil.select())ChannelHandlerAdapter#handlerAdded/Removed、LoggingHandler、Wireshark 抓包