Skip to content

面试题蒸馏卡:Netty

问题:Netty 是什么?为什么快?线程模型怎么设计的?粘包拆包怎么解决?零拷贝是什么?

高频问题与标准答

1. BIO、NIO、AIO 的区别?

BIONIOAIO
模型一连接一线程一请求一线程(多路复用)一有效请求一线程
阻塞阻塞非阻塞非阻塞(内核完成回调)
面向流(单向)缓冲区(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 核数 × 2Math.max(1, cpu*2));bind() 完之后启动。

6. TCP 粘包/拆包怎么解决?

  • 原因:TCP 流式——写大包拆包、小包合并粘包;MSS 分段、MTU 分片。
  • 解决:FixedLengthFrameDecoder(定长)/ LineBasedFrameDecoder(换行)/ DelimiterBasedFrameDecoder(自定义分隔符)/ LengthFieldBasedFrameDecoder(长度字段头,最通用);或自定义编解码器。

7. 什么是 Netty 的零拷贝?

  1. Direct Buffer:堆外直接内存,免堆→直接内存拷贝;
  2. CompositeByteBuf:多 Buffer 逻辑合并,免物理拼接;
  3. FileRegion + transferTo():文件直发目标 Channel,免循环 write;
  4. 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 发送消息有几种方式?

  1. 直接写 Channel → 消息从 Pipeline 尾部开始移动;
  2. 写 ChannelHandlerContext → 从下一个 Handler 开始移动。

12. 序列化协议怎么选?

  • 调试友好/跨语言:JSON、XML。
  • 高性能 RPC:Protobuf(码流小、性能高、跨防火墙)、Thrift(完整 RPC 方案)、Avro(动态语言/Hadoop 生态)。
  • Java 默认序列化:不跨语言、码流大、性能差,不推荐。

追问链

  1. NioEventLoop 循环做什么? 轮询事件(processSelectedKeys)→ 处理 I/O → 处理任务队列(runAllTasks,每 64 个任务检查耗时,防止非 IO 任务饿死 IO)。
  2. ioRatio 是什么? I/O 任务与非 I/O 任务执行时间比,默认 50(各占一半)。
  3. ChannelPipeline 事件传播方向? 入站 head→tail(Inbound Handler),出站 tail→head(Outbound Handler),两种 Handler 互不干扰。
  4. 内存管理怎么做? Arena → Chunk(2048 page)→ Page;大于 8k 走 poolChunkList,小于 8k 走 PoolSubpage;PooledByteBuf 复用 + 引用计数(AtomicIntegerFieldUpdater)回收。
  5. ByteBuf 和 ByteBuffer 区别? ByteBuf 读写索引分开(免 flip)、自动扩容(4M)、支持复合缓冲零拷贝、引用计数。
  6. Netty 4 还是 5? 4 是主流稳定版;5 用 ForkJoinPool 复杂度高收益不明显,不推荐。

常见误解

  • ❌ "Netty 是 Web 服务器" —— 它是网络框架,Tomcat 才是 Servlet 容器。
  • ❌ "零拷贝 = 完全不用拷贝" —— 是减少用户态↔内核态拷贝(数据留内核态直传)。
  • ❌ "NIO 就是异步 IO" —— NIO 是非阻塞 IO,AIO 才是异步 IO(内核完成回调)。
  • ❌ "worker 线程越多越好" —— 默认 CPU×2 已较优;多到上下文切换反而降吞吐。

关联

最近更新