为什么选择用 Netty

为什么选择用 Netty

  • 支持常用应用层协议;
  • 解决传输问题:粘包、半包现象;
  • 支持流量整形;
  • 完善的连接、Idle 等异常处理。

1. 应对 epoll bug

此 bug 的详细地址——传送门,现在的状态依然是未修复,简单说这个 bug 是异常唤醒空转导致 CPU 100% 。看下面这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 创建、配置 ServerSocketChannel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(9998));
serverChannel.configureBlocking(false);

// 创建 Selector
Selector selector = Selector.open();

// 注册
serverChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
selector.select(); // select 可能在无就绪事件时异常返回!

Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> it = readyKeys.iterator();

while (it.hasNext()) {
SelectionKey key = it.next();
... // 处理事件
it.remove();
}
}

这里 selector.select() 方法应该一直阻塞,然而 Java NIO 可能会在没有任何就绪事件的情况下返回!导致 while 逻辑不断执行,最后 CPU 达到 100% 。

Netty 的应对是检测 epoll 空转的次数,如果大于一定阈值,新建 selector 。

大部分框架的解决也都类似,差别仅在检测方式的不同,其后重建 Selector 。

2. 应对 IP_TOS 参数

在使用 http 的 IP_TOS 参数时会抛出异常,传送门

Netty 的方式是绕着走,不支持这个选项。

3. 比原生更友好

Netty 的 API 更加友好:

  • 比如 Java 里的 ByteBuffer 只有一个指针,所以在写完开始读的时候要做 flip 操作,本身是一个 final 的数组,不好扩容,但是 Netty 的 ByteBuf 就更友好了。
  • Netty 有自己的 FastThreadLocal 在高并发下性能更好。

4. 隔离变化

Netty 隔离了变化,屏蔽了细节:

  • JDK 在变化比如 1.4 引入了 NIO ,在 1.7 引入了 AIO ,如果用原生实现就非常复杂,但是如果使用 Netty 就非常方便。
  • Netty 屏蔽了 JDK NIO 的实现细节。

5. 一群人的战斗

Java NIO 至今有 5 千多个 bug issue ,Netty 代码量多达 18w 行,如果我们选择 NIO 就是一个人的战斗,我们可能需要扫一眼这么多 bug 起码能知道遇到了什么问题,Netty 2004 年至今的发展,我们也不会做的比 Netty 更好了。