(一)netty简介
Netty是一个高性能的NIO框架,相比与IO编程需要编写大量的代码,Netty的使用更加简单。Netty的主要功能是负责网络传输,dubbo,rocket MQ以及elasticsearch中都采用Netty做为网络传输框架。
(二)Netty的特性
1.设计
a、 针对多种传输类型的统一接口 - 阻塞和非阻塞
b、 简单但更强大的线程模型
c、真正的无连接的数据报套接字支持
d、链接逻辑支持复用
2.易用性
a、大量的 Javadoc 和 代码实例
除了在 JDK 1.6 + 额外的限制。(一些特征是只支持在Java 1.7 +。可选的功能可能有额外的限制。)
3.性能
a、比核心 Java API 更好的吞吐量,较低的延时
b、资源消耗更少,这个得益于共享池和重用
c、减少内存拷贝(零拷贝模式)
4.健壮性
a、消除由于慢,快,或重载连接产生的 OutOfMemoryError
b、消除经常发现在 NIO 在高速网络中的应用中的不公平的读/写比
5.安全
a、完整的 SSL / TLS 和 StartTLS 的支持
b、行在受限的环境例如 Applet 或 OSG
(三)Netty的特点
-
一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持
-
使用更高效的socket底层,对epoll空轮询引起的cpu占用飙升在内部进行了处理,避免了直接使用NIO的陷阱,简化了NIO的处理方式。
-
采用多种decoder/encoder 支持,对TCP粘包/分包进行自动化处理
-
可使用接受/处理线程池,提高连接效率,对重连、心跳检测的简单支持
-
可配置IO线程数、TCP参数, TCP接收和发送缓冲区使用直接内存代替堆内存,通过内存池的方式循环利用ByteBuf
-
通过引用计数器及时申请释放不再引用的对象,降低了GC频率
-
使用单线程串行化的方式,高效的Reactor线程模型
-
大量使用了volitale、使用了CAS和原子类、线程安全类的使用、读写锁的使用
(四)Netty的零拷贝实现
Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。堆内存多了一次内存拷贝,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。ByteBuffer由ChannelConfig分配,而ChannelConfig创建ByteBufAllocator默认使用Direct Buffer
CompositeByteBuf 类可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。addComponents方法将 header 与 body 合并为一个逻辑上的 ByteBuf, 这两个 ByteBuf 在CompositeByteBuf 内部都是单独存在的, CompositeByteBuf 只是逻辑上是一个整体
通过 FileRegion 包装的FileChannel.tranferTo方法 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel,避免了传统通过循环write方式导致的内存拷贝问题。
通过 wrap方法, 我们可以将 byte[] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象, 进而避免了拷贝操作。
Selector BUG:若Selector的轮询结果为空,也没有wakeup或新消息处理,则发生空轮询,CPU使用率100%,
Netty的解决办法:对Selector的select操作周期进行统计,每完成一次空的select操作进行一次计数,若在某个周期内连续发生N次空轮询,则触发了epoll死循环bug。重建Selector,判断是否是其他线程发起的重建请求,若不是则将原SocketChannel从旧的Selector上去除注册,重新注册到新的Selector上,并将原来的Selector关闭。