NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通信 IO 模型之关系?


一:NETTY 是什么?


Netty 是什么?  这个问题其实百度上一搜一堆。 这是官方话的描述:Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 能够确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty至关于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。html

其实没那么复杂,用通俗易懂的话来说java


1.1  NETTY  是一个框架

  

NETTY 是一个框架,web

这个框架作了什么事情了,作了一件 Rpc 底层通信对接的事情,编程

Rpc 底层通顺采用什么方式呢,就是采用基于SOCKET 的TCP/UDP (NIO+Reactor ) 长链接模式进行通信(重点)服务器

那么NETTY 框架在对接系统级别的通信层以后 又以编程接口的模式提供给App层。网络


1.2 NETTY  是基于  Socket IO 通信模型中的 NIO+Reactor 模型构建的

       NETTY 是基于NIO 的客户端,服务端编程框架。正式由于如此,使得NETTY  在处理高并发量的时候,有很大的线程优点。那么咱们接下来要讲讲什么是NIO 模型?并发

    对应NIO(Non-Blocking I/O) 模型的 对立模型就是BIO(Blocking I/O) 模型。除此以外还有一种AIO 模型(不作讲解)。 咱们先了解下BIO 模型。框架

  •   了解下  BIO  
  1.   BIO 在系统内核中的模型
eAVNZfR

从上图中能够看到:socket

当用户线程发出IO请求以后,内核会去查看数据是否就绪,若是没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪以后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。高并发

典型的阻塞IO模型的例子为:

data = socket.read();

若是数据没有就绪,就会一直阻塞在read方法。而且新soket 链接过来,都会产生新的socket 线程管理,以下图所示。





timg-2



        从上面图中咱们能够看出在BIO 模型中,能够清楚的了解到 :一个套接字须要使用一个线程处理,它的过程就是创建链接、读数据、写数据,然而在这些过程当中都有可能会发生阻塞。这就是为何咱们首先会接触到这种方式的缘由,由于它简单,一个线程只处理一个Socket,但若是是Server端,在并发链接时就须要更多的线程才能完成工做。咱们熟悉的 .NET FRAMEWORK WEB 应用的 寄宿主 IIS 就使用此种模式。

    

         下面这张图描述了BIO 在系统内核中的场景图: 客人来了,就让一个新的服务员服务,只等到客人走了,这个服务员的工做任务也就完成了。 说明这个餐厅的服务质量很好,可是效率很低,服务员的利用率跟饱和度低,占用资源浪费,而且成本增长。

   socketIO



  • 了解下NIO

             NIO 分为两种,一种是传统的NIO 由于传统的NIO 为早期的版本,后来系统内核增长了 NIO+Reactor

咱们在来看一张图早期版本NIO 内核SOCKET 管理模型:


timg---3 

从上图了解到:

早期的NIO 的原理:当用户线程发起一个read操做后,并不须要等待,而是立刻就获得了一个结果。若是结果是一个error时,它就知道数据尚未准备好,因而它能够再次发送read操    做。一旦内核中的数据准备好了,而且又再次收到了用户线程的请求,那么它立刻就将数据拷贝到了用户线程,而后返回。因此事实上,在非阻塞IO模型中,用户线程须要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。

典型的传统非阻塞IO模型通常以下:


while(true){

data = socket.read();

if(data!= error){

处理数据

break;

}

}

  可是对于早期传统非阻塞IO(NIO)就有一个很是严重的问题,在while循环中须要不断地去询问内核数据是否就绪,这样会致使CPU占用率很是高,所以通常状况下很 少使用while循环这种方式来读取数据。


  为了解决这个问题,后期的NIO 版本增长 引入了Reactor 模式,也就是 (线程+SELECT)。也就是如今RPC 服务框架基于底层内核用的最多的NIO+Reactor   模型。

 

  • NIO+Reactor  模型(NIO多路复用模型):

        一样咱们了解下NIO多路复用模型的系统内核SOCKET维护流程:

      2eAVjiF (1)

(1)当用户进程调用了select (这个select 很是关键,下面会讲到),那么整个进程会被block;

(2)而同时,kernel会“监视”全部select负责的socket;

(3)当任何一个socket中的数据准备好了,select就会返回;

(4)这个时候用户进程再调用read操做,将数据从kernel拷贝到用户进程(空间)


(多路复用IO 模型) 是基于事件驱动的思想,采用了Reactor模式,相对于BIO,NIO一个明显的优点就是不须要为每个Socket套接字分配一个线程,而是在一个线程中能够处理多个Socket套接字相关的工做。感兴趣的能够去了解一下Reactor模式,在这里给一个连接 -> 详解Reactor

 


timg1

从上面图中能够看出:

      多路复用IO模式,经过一个线程就能够管理多个socket,只有当socket真正有读写事件发生才会占用资源来进行实际的读写操做。所以,多路复用IO比较适合链接数比较多的状况。

     在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操做。由于在多路复用IO模型中,只须要使用一个线程就能够管理多个socket,系统不须要创建新的进程或者线程,也没必要维护这些线程和进程,而且只有在真正有socket读写事件进行时,才会使用IO资源,因此它大大减小了资源占用

  另外多路复用IO为什么比非阻塞IO模型的效率高是由于在非阻塞IO中,不断地询问socket状态时经过用户线程去进行的,而在多路复用IO中,轮询每一个socket状态是内核在进行的,这个效率要比用户线程要高的多。

  不过要注意的是,多路复用IO模型是经过轮询的方式来检测是否有事件到达,而且对到达的事件逐一进行响应。所以对于多路复用IO模型来讲,一旦事件响应体很大,那么就会致使后续的事件迟迟得不处处理,而且会影响新的事件轮询。


下面这张是对NIO+Reactor  的系统内核的场景描述图: 多个客人来了,有一个服务员先来接待,而且同步复制全部的客人的信息给相关的处理部门,部门根据本身感兴趣的来处理的相对应的的消息。


NIO


 


   总结从场景图中能够看出/或者从众看各个系列文章: NIO多路复用模型是基于 一个线程接待了多个客户端套接字的管理,那么反过来讲,在这个线程中产生了一个管理者,那么这个管理者称之为 selector  那么这个 (线程+selector ) 是属于netty 层呢仍是属于系统级别层呢? 咱们以上所述的,都是属于系统自己级别,也就是说 (线程+selector )  仍是属于系统级别层的,那么netty 作了些什么呢? NETTY 它是基于系统的NIO +Reactor模型构建的,而且实现了 与操做系统给的NIO+Reactor 模型中的 selector 对象 进行对接,将它封装NETTY框架之中以后,提供了一个易于操做的使用模式和接口,用户使用起来更加方便便捷。


          那么NETTY 与多路复用模型IO 中的 SELECTOR 对象又有什么关系呢? 咱们先了解下具体的SELECTOR 管理了哪些内容? 咱们先来看一张图:

        


u=1276492790,3867025050&fm=11&gp=0


       上图中很清楚的了解到: 多路复用模型中的Selector 维护了 每一个socket 链接的channel ,并为这个channel产了相对于的key ,  放入 MAP 中,从程序角度讲,系统的多路复用器(SELECTOR)  中维护了 map<string ,channel> 对应的集合关系。  从NETTY角度来说,NETTY 关心的是 系统多路复用IO 模型的 SELECTOR ,由于经过它,就能获取到读写消息事件,而且新的链接的注册事件,还有链接断开事件等,而且经过SELECTOR 找到对应的 socket channel ,就能够对具体的链接进行读写操做了。


三:NETTY  能作什么?


     咱们使用通用的应用程序或者类库来实现互相通信,好比,咱们常用一个 HTTP 客户端库来从 web 服务器上获取信息,或者经过 web 服务来执行一个远程的调用。

  然而,有时候一个通用的协议或他的实现并无很好的知足需求。好比咱们没法使用一个通用的 HTTP 服务器来处理大文件、电子邮件以及近实时消息,好比金融信息和多人游戏数据。咱们须要一个高度优化的协议来处理一些特殊的场景。例如你可能想实现一个优化了的 Ajax 的聊天应用、媒体流传输或者是大文件传输器,你甚至能够本身设计和实现一个全新的协议来准确地实现你的需求。

  另外一个不可避免的状况是当你不得不处理遗留的专有协议来确保与旧系统的互操做性。在这种状况下,重要的是咱们如何才能快速实现协议而不牺牲应用的稳定性和性能。

而且借助NETTY ,能够 快速搭建一套 基于NIO 的RPC 服务框架体系。咱们熟知的 java 的 dobule ,RMI、Hessian。

可是:NETTY 也有本身的缺点:


         NIO 的 Reactor模式在IO读写数据时仍是在同一个线程中实现的,即便使用多个Reactor机制的状况下,那些共享一个Reactor的Channel若是出现一个长时间的数据读写,会影响这个Reactor中其余Channel的相应时间,好比在大文件传输时,IO操做就会影响其余Client的相应时间,于是对这种操做,使用传统的Thread-Per-Connection或许是一个更好的选择,或则此时使用Proactor模式。


   所以在开发技术选型的时候,不能盲目的选择,仍是配合业务场景,根据实际状况来选择.

相关文章
相关标签/搜索