适用读者:想搞懂"为什么 Netty 能撑高并发"的人。
前置:S02-B09(IO 多路复用)、S04-J06(NIO)。
覆盖旧文:1846(240) 1088(108) 1089(84) 1090(87) 1092(95) 1093(69) 1094(99) 1095(76) 1096(75) 1097(87) 1091(93) 2627(204) 2319(44) 504(40) = 1,401 点。
覆盖扩展:E-S17-016(线程模型与粘包)。
上一篇:S17-A02 · 链路追踪与可观测性
下一篇:S17-X01 · 八股速查。
1. 一句话结论
Netty 快不是因为"某个黑科技",而是把四件事做到极致:事件循环(Reactor)、零拷贝、对象池、无锁化。
| 机制 | 作用 |
|---|---|
| Reactor 线程模型 | 少量线程管大量连接(S02-B09) |
| 零拷贝 | 减少内核/用户态复制 |
| ByteBuf + 对象池 | 减少 GC 与内存分配 |
| 无锁化设计 | 减少竞争 |
2. 线程模型:Boss + Worker(E-S17-016)
BossGroup(1 线程):接收连接
WorkerGroup(N 线程):处理读写
↓
每个 Channel 绑定一个 EventLoop(单线程处理它的所有事件)
"为什么单线程处理一个连接":避免并发修改 Channel 状态——这正是它"无锁化"的来源。
判据:"业务处理耗时长吗?" 长 → 交给业务线程池,别堵 EventLoop(与 S05-B05 的"别堵线程池"同源)。
3. 零拷贝的两层含义(A-1092)
| 层 | 说明 |
|---|---|
| OS 层 | sendfile/mmap 减少复制(与 Kafka 同) |
| Netty 层 | CompositeByteBuf/slice 避免内存拷贝 |
"零拷贝不是真的零次":是"减少不必要的 CPU 拷贝",DMA 复制仍存在。
4. ByteBuf 与对象池(A-1094/A-1095)
| 对比 | JDK ByteBuffer | Netty ByteBuf |
|---|---|---|
| 读写指针 | 一个 position(要 flip) | 两个指针(读/写独立) |
| 动态扩容 | 不支持 | ✅ |
| 池化 | ❌ | ✅(PooledByteBufAllocator) |
"为什么池化重要":高并发下频繁分配/回收大 buffer → GC 压力(与 S05-J04 的 TLAB 优化同思路)。
5. 粘包与拆包(A-1090)
TCP 是字节流,没有消息边界(S02-B04 的核心结论)。Netty 提供解码器:
| 解码器 | 适用 |
|---|---|
FixedLengthFrameDecoder |
定长 |
LineBasedFrameDecoder |
换行分隔 |
LengthFieldBasedFrameDecoder |
长度前缀(最常用) |
DelimiterBasedFrameDecoder |
自定义分隔符 |
判据:"协议里有长度字段吗?" 有 → LengthFieldBasedFrameDecoder;没有 → 必须先定协议。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "Netty 用多线程处理一个连接" | 一个 Channel 绑一个 EventLoop |
| "零拷贝=完全不复制" | 减少 CPU 拷贝 |
| "ByteBuf 不用释放" | 池化需 release() |
| "TCP 有消息边界" | 字节流,需应用层协议 |
| "业务逻辑可以直接放 EventLoop" | 会阻塞整条连接 |
7. 自检(架构师版)
- Boss/Worker 分工?
- 为什么一个 Channel 只绑一个 EventLoop?
- 零拷贝的两层含义?
- ByteBuf 相比 ByteBuffer 的三个优势?
- 粘包的本质与解码器选择?
8. 下一篇
S17-X01 · 分布式八股速查
最后一篇是附录索引,随后进入 S20/S21 的 AI 工程系列。
本篇属于系列《S17 · 分布式与消息队列》。旧文来源:A-1846/1088/1089/1090/1092/1093/1094/1095/1096/1097/1091/2627/2319/504;扩展点 E-S17-016。