Netty基础知识
一、Netty零拷贝?
-
Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
-
Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。
-
Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。
传统的数据发送方式是 :
File.read(bytes) Socket.send(bytes)
这种方式需要四次数据拷贝和四次上下文切换:
- 数据从磁盘读取到内核的read buffer
- 数据从内核缓冲区拷贝到用户缓冲区
- 数据从用户缓冲区拷贝到内核的socket buffer
- 数据从内核的socket buffer拷贝到网卡接口的缓冲区
通过java的FileChannel.transferTo方法,可以避免上面两次多余的拷贝(当然这需要底层操作系统支持)
- 调用transferTo,数据从文件由DMA引擎拷贝到内核read buffer
- 接着DMA从内核read buffer将数据拷贝到网卡接口buffer
上面的两次操作都不需要CPU参与,所以就达到了零拷贝。
二、netty的优势?
- 传输快,Netty是基于NIO实现了这种Reactor模型,Boss线程组用来专门处理连接的建立,SubReactor专门用来处理IO的读写以及任务的处理。这种线程模型在充分利用CPU性能的情况下支撑大量的并发连接。
- 内存使用少,ByteBufAllocator对象池。池化ByteBuf实例以提高性能并最小化内存碎片,后者每次调用时都返回一个新的实例。零拷贝。支持DirectBuffer的使用,通过JVM的本地调用分配内存,这可避免每次调用本地I / O操作之前(或之后)将缓冲区的内容复制到(或从)中间缓冲区
- API简单,网络编程一般都比较复杂,更面临着IO读写以及线程安全问题问题要处理,Netty针对网络编程、io读写、线程安全等问题做了大量封装,使API更简单易用。
- Netty非常稳定,netty解决了JDK中的nio的bug,而且应用在一些比较流行的框架中
三、netty的线程模型
netty主要是实现reactor的主从多线程模型。