NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?
一:NETTY 是什么?
Netty 是什么? 这个问题其实百度上一搜一堆。 这是官方话的描述:Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。
其实没那么复杂,用通俗易懂的话来讲:
1.1 NETTY 是一个框架
NETTY 是一个框架,
这个框架做了什么事情了,做了一件 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
BIO 在系统内核中的模型
从上图中可以看到:
当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。
典型的阻塞IO模型的例子为:
data = socket.read();
如果数据没有就绪,就会一直阻塞在read方法。并且新soket 连接过来,都会产生新的socket 线程管理,如下图所示。
从上面图中我们可以看出在BIO 模型中,可以清楚的了解到 :一个套接字需要使用一个线程处理,它的过程就是建立连接、读数据、写数据,然而在这些过程中都有可能会发生阻塞。这就是为什么我们首先会接触到这种方式的原因,因为它简单,一个线程只处理一个Socket,但如果是Server端,在并发连接时就需要更多的线程才能完成工作。我们熟悉的 .NET FRAMEWORK WEB 应用的 寄宿主 IIS 就使用此种模式。
下面这张图描述了BIO 在系统内核中的场景图: 客人来了,就让一个新的服务员服务,只等到客人走了,这个服务员的工作任务也就完成了。 说明这个餐厅的服务质量很好,但是效率很低,服务员的利用率跟饱和度低,占用资源浪费,并且成本增加。
- 了解下NIO
NIO 分为两种,一种是传统的NIO 因为传统的NIO 为早期的版本,后来系统内核增加了 NIO+Reactor
我们在来看一张图早期版本NIO 内核SOCKET 管理模型:
从上图了解到:
早期的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维护流程:
(1)当用户进程调用了select (这个select 非常关键,下面会讲到),那么整个进程会被block;
(2)而同时,kernel会“监视”所有select负责的socket;
(3)当任何一个socket中的数据准备好了,select就会返回;
(4)这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程(空间)
(多路复用IO 模型) 是基于事件驱动的思想,采用了Reactor模式,相对于BIO,NIO一个明显的优势就是不需要为每一个Socket套接字分配一个线程,而是在一个线程中可以处理多个Socket套接字相关的工作。感兴趣的可以去了解一下Reactor模式,在这里给一个链接 -> 详解Reactor
从上面图中可以看出:
多路复用IO模式,通过一个线程就可以管理多个socket,只有当socket真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO比较适合连接数比较多的情况。
在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用
另外多路复用IO为何比非阻塞IO模型的效率高是因为在非阻塞IO中,不断地询问socket状态时通过用户线程去进行的,而在多路复用IO中,轮询每个socket状态是内核在进行的,这个效率要比用户线程要高的多。
不过要注意的是,多路复用IO模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用IO模型来说,一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。
下面这张是对NIO+Reactor 的系统内核的场景描述图: 多个客人来了,有一个服务员先来接待,并且同步复制所有的客人的信息给相关的处理部门,部门根据自己感兴趣的来处理的相对应的的消息。
总结:从场景图中可以看出/或者从众看各个系列文章: NIO多路复用模型是基于 一个线程接待了多个客户端套接字的管理,那么反过来说,在这个线程中产生了一个管理者,那么这个管理者称之为 selector 那么这个 (线程+selector ) 是属于netty 层呢还是属于系统级别层呢? 我们以上所述的,都是属于系统本身级别,也就是说 (线程+selector ) 还是属于系统级别层的,那么netty 做了些什么呢? NETTY 它是基于系统的NIO +Reactor模型构建的,并且实现了 与操作系统给的NIO+Reactor 模型中的 selector 对象 进行对接,将它封装NETTY框架之中之后,提供了一个易于操作的使用模式和接口,用户使用起来更加方便便捷。
那么NETTY 与多路复用模型IO 中的 SELECTOR 对象又有什么关系呢? 我们先了解下具体的SELECTOR 管理了哪些内容? 我们先来看一张图:
上图中很清楚的了解到: 多路复用模型中的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模式。
因此在开发技术选型的时候,不能盲目的选择,还是配合业务场景,根据实际情况来选择.
NetCore Netty 框架 BT.Netty.RPC 系列随讲 二 WHO AM I 之 NETTY/NETTY 与 网络通讯 IO 模型之关系?的更多相关文章
- 如何在Visual Studio 2017中使用C# 7+语法 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建NetCore应用框架之实战篇系列 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 NetCore入门篇:(十二)在IIS中部署Net Core程序
如何在Visual Studio 2017中使用C# 7+语法 前言 之前不知看过哪位前辈的博文有点印象C# 7控制台开始支持执行异步方法,然后闲来无事,搞着,搞着没搞出来,然后就写了这篇博文,不 ...
- NetCore Netty 框架 BT.Netty.RPC 系列随讲 —(前序) REST API 与 RPC 经典网络基础服务架构
在服务体系架构内,我们所知道的,有两种请求模型: Http 请求模型,以及 RPC 请求模型.因此,在一个互联网请求模型架构上,都是这两种的请求模型的向互组合. 下面给出两种常见的互联网经典基础架构图 ...
- 构建NetCore应用框架之实战篇系列
构建NetCore应用框架之实战篇 构建NetCore应用框架之实战篇(一):什么是框架,如何设计一个框架 构建NetCore应用框架之实战篇(二):BitAdminCore框架定位及架构 构建Net ...
- 基于netty框架的轻量级RPC实现(附源码)
前言 Rpc( Remote procedure call):是一种请求 - 响应协议.RPC由客户端启动,客户端向已知的远程服务器发送请求消息,以使用提供的参数执行指定的过程.远程服务器向客户端发送 ...
- 构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.简介 1.登录功能完成后,框架的雏形已经形成,有必要进行复习. 2 ...
- 构建NetCore应用框架之实战篇(六):BitAdminCore框架架构小结
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.小结 1.前面已经完成框架的第一个功能,本篇做个小结. 2.直接上 ...
- 构建NetCore应用框架之实战篇(五):BitAdminCore框架1.0登录功能设计实现及源码
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.设计原则 1.继承前面框架架构思维,设计以可读性作为首要目标. 2 ...
- 构建NetCore应用框架之实战篇(四):BitAdminCore框架1.0登录功能细化及技术选型
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.BitAdminCore框架1.0版本 1.1.0版本是指最小版本 ...
- 构建NetCore应用框架之实战篇(三):BitAdminCore框架功能规划选择
本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.BitAdminCore功能规划 如何选择框架的落地功能,前篇文章 ...
随机推荐
- linux基础常用语句--新手
查询:ls查看全部内容:ls -n删除:rm -rf 文件名创建目录: mkdir解压:rpm -验证是否安装:rpm -p 文件名rpm -ivh --nodeps 不需要前置条件的安装查询当前路径 ...
- python3爬虫-通过requests获取安居客房屋信息
import requests from fake_useragent import UserAgent from lxml import etree from http import cookiej ...
- react入门----事件监听
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 08.C语言:特殊函数
C语言:特殊函数 1.递归函数: 与普通函数比较,执行过程不同,该函数内部调用它自己,它的执行必须要经过两个阶段:递推阶段,回归阶段: 当不满足回归条件,不再递推: #include <stdi ...
- PAT 1127 ZigZagging on a Tree
Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can ...
- HUST 1214 Cubic-free numbers II
Cubic-free numbers II Time Limit: 10000ms Memory Limit: 131072KB This problem will be judged on HUST ...
- HDU 4598 Difference
Difference Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total ...
- HDU 1018 阶乘数的位数
题目大意: 将一个数开阶乘后得到的值,来求这个值的位数 n! = 1*2*3*4...*n 对于求一个数的位数的方法为ans = lg(n!) + 1 那么就可以看作 ans = lg(1) + lg ...
- Codeforces Round #254 (Div. 1) C DZY Loves Colors
http://codeforces.com/contest/444/problem/C 题意:给出一个数组,初始时每个值从1--n分别是1--n. 然后两种操作. 1:操作 a.b内的数字是a,b内 ...
- python整数转ASCII码
# *-* coding:utf-8 *-* import binascii data = [1441465642, 251096121, -870437532, -944322827, 647240 ...