主题
面试题蒸馏卡:Netty
问题:Netty 是什么?为什么快?线程模型怎么设计的?粘包拆包怎么解决?零拷贝是什么?
高频问题与标准答
1. BIO、NIO、AIO 的区别?
| BIO | NIO | AIO | |
|---|---|---|---|
| 模型 | 一连接一线程 | 一请求一线程(多路复用) | 一有效请求一线程 |
| 阻塞 | 阻塞 | 非阻塞 | 非阻塞(内核完成回调) |
| 面向 | 流(单向) | 缓冲区(Channel 双向) | 缓冲区 |
- NIO 三组件:Channel / Buffer / Selector(单线程管多 Channel)。
- 伪异步 IO = BIO + 线程池,仍是瓶颈。
2. Netty 是什么?为什么要用它?
- 基于 NIO 的异步事件驱动网络框架,封装 JDK NIO 的复杂性。
- 解决 JDK NIO 四大痛点:API 繁杂、需多线程+网络双技能、可靠性补齐难(断连/半包/拥塞)、epoll 空轮询 bug(CPU 100%)。
- 应用:Dubbo / RocketMQ / Elasticsearch / gRPC 的通信底座。
3. Netty 核心组件有哪些?
Channel(网络操作抽象)· EventLoop(1 线程 + 1 Selector 管多个 Channel)· EventLoopGroup(线程池,默认 CPU×2)· ChannelFuture(异步结果,addListener 回调 / sync 转同步)· ChannelHandler(事件处理)· ChannelPipeline(Handler 链)· Bootstrap/ServerBootstrap(启动引导)。
4. 线程模型怎么设计的?
- 基于主从 Reactor 多线程模型的变体:bossGroup(MainReactor)收 accept → 封装 NioSocketChannel → 注册给 workerGroup(SubReactor + Worker 同池)处理 read/write。
- 三种模型:单线程(全在一个线程,高负载不行)/ 多线程(一个 Acceptor + 线程池,百万连接瓶颈)/ 主从多线程(Netty 采用)。
- 关键:一个 Channel 只绑定一个 EventLoop 线程,串行执行免锁;业务 Handler 不能阻塞,否则卡死该线程所有 Channel。
5. 默认起多少线程?何时启动?
CPU 核数 × 2(Math.max(1, cpu*2));bind() 完之后启动。
6. TCP 粘包/拆包怎么解决?
- 原因:TCP 流式——写大包拆包、小包合并粘包;MSS 分段、MTU 分片。
- 解决:
FixedLengthFrameDecoder(定长)/LineBasedFrameDecoder(换行)/DelimiterBasedFrameDecoder(自定义分隔符)/LengthFieldBasedFrameDecoder(长度字段头,最通用);或自定义编解码器。
7. 什么是 Netty 的零拷贝?
- Direct Buffer:堆外直接内存,免堆→直接内存拷贝;
- CompositeByteBuf:多 Buffer 逻辑合并,免物理拼接;
- FileRegion +
transferTo():文件直发目标 Channel,免循环 write; wrap():byte[]/Buffer 包装为 ByteBuf 零拷贝。
8. epoll 空轮询 bug 是什么?Netty 怎么解决的?
- JDK NIO 的 Selector 空轮询导致 CPU 100%(JDK 6u18 声明修复但 1.7 仍有)。
- Netty:
selectCnt记录空轮询次数,连续 512 次 →rebuildSelector()新建 Selector、重注册 Channel、关闭旧 Selector。
9. 心跳机制怎么实现?
- TCP
SO_KEEPALIVE灵活性不够,应用层自定义心跳。 - Netty
IdleStateHandler:readerIdleTime / writerIdleTime / allIdleTime;空闲发 PING-PONG 保活,服务端清闲置会话、客户端检测断线。
10. Netty 和 Tomcat 的区别?
Tomcat 是基于 HTTP 的 Servlet 容器(Web 服务器);Netty 是异步网络框架,可通过编解码自定义任意协议(HTTP/FTP/WebSocket/RPC/Redis Proxy/MySQL Proxy)。
11. Netty 发送消息有几种方式?
- 直接写 Channel → 消息从 Pipeline 尾部开始移动;
- 写 ChannelHandlerContext → 从下一个 Handler 开始移动。
12. 序列化协议怎么选?
- 调试友好/跨语言:JSON、XML。
- 高性能 RPC:Protobuf(码流小、性能高、跨防火墙)、Thrift(完整 RPC 方案)、Avro(动态语言/Hadoop 生态)。
- Java 默认序列化:不跨语言、码流大、性能差,不推荐。
追问链
NioEventLoop循环做什么? 轮询事件(processSelectedKeys)→ 处理 I/O → 处理任务队列(runAllTasks,每 64 个任务检查耗时,防止非 IO 任务饿死 IO)。ioRatio是什么? I/O 任务与非 I/O 任务执行时间比,默认 50(各占一半)。- ChannelPipeline 事件传播方向? 入站 head→tail(Inbound Handler),出站 tail→head(Outbound Handler),两种 Handler 互不干扰。
- 内存管理怎么做? Arena → Chunk(2048 page)→ Page;大于 8k 走 poolChunkList,小于 8k 走 PoolSubpage;PooledByteBuf 复用 + 引用计数(AtomicIntegerFieldUpdater)回收。
- ByteBuf 和 ByteBuffer 区别? ByteBuf 读写索引分开(免 flip)、自动扩容(4M)、支持复合缓冲零拷贝、引用计数。
- Netty 4 还是 5? 4 是主流稳定版;5 用 ForkJoinPool 复杂度高收益不明显,不推荐。
常见误解
- ❌ "Netty 是 Web 服务器" —— 它是网络框架,Tomcat 才是 Servlet 容器。
- ❌ "零拷贝 = 完全不用拷贝" —— 是减少用户态↔内核态拷贝(数据留内核态直传)。
- ❌ "NIO 就是异步 IO" —— NIO 是非阻塞 IO,AIO 才是异步 IO(内核完成回调)。
- ❌ "worker 线程越多越好" —— 默认 CPU×2 已较优;多到上下文切换反而降吞吐。
关联
- 总览:Netty技术栈总览
- 原理:概念卡片:Netty线程模型与高性能
- 通信底座:面试题蒸馏卡:Dubbo · [概念卡片:Dubbo RPC框架](./概念卡片:Dubbo RPC框架)
- 网络基础:计算机网络技术栈总览