当前位置: 首页 > 图灵资讯 > 技术篇> Netty

Netty

来源:图灵教育
时间:2023-06-13 09:24:51

要了解Netty,首先要了解Java提供的Api,包括BIO(同步阻塞)和NIO(同步非阻塞和AIO(异步非阻塞)

BIO

blocking IO。最容易理解和实现的IO工作模式,应用程序向操作系统要求网络IO操作,然后应用程序将继续等待;另一方面,操作系统将等待,直到数据传输到监控端口;操作系统将数据发送到应用程序;最后,应用程序接收数据并解除等待状态。

Netty_客户端

缺点:当客户端有连接请求时,服务器端需要启动一个线程进行处理。即使连接不做任何事情,或者很少使用频率,当线程数量达到操作系统的限制时,服务器的线程费用可能会延迟或拒绝新的连接请求。

优点:程序易于理解

NIO

NIO :JDK1.4提出的同步非阻塞IO。服务器实现模式是一个要求和一个线程。客户端发送的连接请求将注册为多路复用器。多路复用器只有在查询连接有I/O请求时才启动一个线程。基于Reactor模式的NIO可以参考 Reactor模式),Select/poll模型(Linux22),其Select底部调用操作系统.6使用epoll)连续轮询,直到有数据可操作,这实际上是一个同步IO。当发现数据操作时,IO操作不会被阻塞,即非阻塞IO。此外,在这种模型下,从通知应用程序的数据可读性,到read调用将外部数据加载到核心空间,然后从核心空间复制到用户空间需要一定的时间间隔,这也将减少整体数据吞吐量。

NIO有三个核心部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器)

buffer缓冲区:

缓冲区本质上是一个内存,可以写入数据,然后读取数据。这个内存被包装成NIO buffer对象提供了一组方法,方便访问该块内存。与数组的直接操作相比,Buffer API更容易操作和管理

Channel(通道):

Java NIO的通道类似于流量,但也有一些不同:数据可以从通道中读取,数据可以写到通道中。但是流量(input或output)读写通常是单向的。通道可以支持读写缓冲区的读写,也可以支持异步读写

Selector选择器:

Selector是Java NIO组件可以检查一个或多个NIO通道,并确定哪些通道已经准备好读取或写入。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接,提高效率。

Netty_数据_02

具有以下特点:

  • 以块为基础的NIO(Block)是的,它以块为基本单位处理数据 (硬盘上存储的单位也按Block存储,性能优于基于流的方式)
  • 为所有原始类型提供服务(Buffer)缓存支持
  • 增加通道(Channel)对象,作为新的原始 I/O 抽象
  • 支撑锁(我们在平时使用的时候经常会看到一些.lock文件表明有线程正在使用该锁。当线程释放锁时,将删除该文件,以便其他线程可以继续获得该锁)和内存映射文件的文件访问接口
  • 基于Selector的异步网络I/O

总结:

  1. NIO将数据准备好,然后移交给应用程序进行处理。数据的读写过程仍在应用程序线程中完成,只将等待时间剥离到单独的线程中。
  2. 节省数据准备时间(因为Selector可以重用)

NIO源码分析

AIO

AIO的特点:

  1. 看完再通知我
  2. IO不会加速,只是在阅读后通知
  3. 使用回调函数处理业务

在理解NIO的基础上,看AIO,区别在于AIO是在读写过程完成后再调用回调函数。

NIO是同步非阻塞的

AIO是异步非阻塞的

由于NIO的读写过程仍在应用程序线程中完成,因此NIO不适合那些长时间读写的人。

AIO的读写过程只有在完成后才会被通知,因此AIO能够胜任重量级、读写过程长的任务。

为什么Netty并发高?

Niotty是一个基于NIO的基础(Nonblocking I/O,与BIO相比,非阻塞IO)开发的网络通信框架(Blocking I/O,阻塞IO),他的并发性能有了很大的提高,两张图让你知道BIO和NIO的区别:

BIO

NIO

从这两张图中可以看出,NIO的单线程能处理连接的数量远远高于BIO,为什么单线程能处理更多的连接呢?原因是图2Selector。 当一个连接建立起来时,他有两个步骤要做。第一步是接收客户端发送的所有数据,第二步是在服务端处理请求业务后返回给客户端。NIO和BIO的区别主要在第一步。 在BIO中,等待客户端发送数据的过程被堵塞,导致一个线程只能处理一个请求,而机器可以支持的最大线程数量有限,这就是为什么BIO不能支持高并发性。 在NIO中,当Socket建立时,Thread不会阻止接受Socket,而是将此请求交给Selector。Selector将继续访问所有的Socket。一旦Socket建立完成,他将通知Thread,然后Thread将处理数据并返回到客户端——这个过程不会被阻止,这样,一个Thread就可以处理更多的请求。

为什么Nettty快速传输?

事实上,Netty的快速传输也取决于NIO的一个特性——零拷贝。众所周知,Java内存包括堆内存、堆内存和字符串常量池,其中堆内存是占用内存空间最大的部分,也是Java对象存储的地方。一般来说,如果我们的数据需要从IO读取到堆内存,我们需要通过Socket缓冲区,也就是说,数据将被复制两次才能到达他的终点。如果数据量大,将造成不必要的资源浪费。 针对这种情况,Netty使用了NIO中的另一个主要特征——零副本。当他需要接收数据时,他会在堆内存之外打开一个内存,数据会直接从IO读取内存。在Netty中,这些数据可以通过Bytebuf直接操作,从而加快传输速度。