【攻破技术盲点】— 网络IO模型的分析(上)

简介: 【攻破技术盲点】— 网络IO模型的分析(上)

Linux的网络IO模型


网络IO的本质是socket的读写,socket在Linux中被抽象为流IO可以理解为对流的操作。



IO的分类和范畴


IO本身可以分为内存IO、网络IO和磁盘IO还有缓存IO等,一般讨论IO时更多是指后(网络IO和磁盘IO,因为这两个是最慢的哈哈),此处特别分析和说明网络IO




操作处理的分类


阻塞/非阻塞


针对函数/方法的实现方式而言,即数据就绪之前是立刻返回还是等待,即发起IO请求后是否会阻塞


阻塞IO机制


阻塞IO情况下,当用户调用read后,用户线程会被阻塞,等内核数据准备好并且数据从内核缓冲区拷贝到用户态缓存区后read才会返回。可以看到是阻塞的两个部分


  • CPU把数据从磁盘读到内核缓冲区。


  • CPU把数据从内核缓冲区拷贝到用户缓冲区。


image.png

非阻塞IO机制

image.png

  • 非阻塞IO发出read请求后发现数据没准备好,会继续往下执行,此时应用程序会不断轮询polling内核询问数据是否准备好,当数据没有准备好时,内核立即返回EWOULDBLOCK错误。


  • 直到数据被拷贝到应用程序缓冲区,read请求才获取到结果。并且你要注意!这里最后一次 read 调用获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。



同步/异步


IO读操作指数据流经:网络 -> 内核缓冲区 -> 用户内存


  • 同步和异步的主要区别在于数据从内核缓冲区 -> 用户内存这个过程需不需要用户进程等待


  • 等待内核态准备数据结束之后,会自动回通知用户态的线程进行读取信息数据,此时之前用户态的线程不需要等待,可以去做其他操作。


对于一个网络IO,会涉及到两个系统对象,一个是调用这个IO的process(or thread)【用户态】,另一个就是系统内核(kernel)【内核态】



当一个用户态发生read操作发生时,它会经历两个阶段:


  • 第一阶段:用户态线程等待内核态的数据准备 (Waiting for the data to be ready)


  • 第二阶段:用户态线程,将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)。


  • 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区


  • 第二步:把数据从内核缓冲区复制到(用户态)应用进程缓冲区。网络应用处理的是两大类问题:网络IO、数据计算。前者给应用带来的性能瓶颈更大。



网络IO的模型大致有如下几种:


  • 同步模型(synchronous IO)


  • 阻塞IO模型(blocking IO)


  • 非阻塞IO模型(non-blocking IO)


  • 多路复用IO模型(multiplexing IO)


  • 信号驱动IO模型(signal-driven IO)


  • 异步IO(asynchronous IO)




阻塞IO模型(blocking IO)


Linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程如下:


image.png

当用户进程调用了recvfrom这个系统调用,如上所述,会有两个阶段


准备数据:


  • 很多时候数据在一开始还没有到达,这个时候kernel就要等待足够的数据到来。而用户进程会一直阻塞。


  • 当kernel等到数据准备好了,它会将数据从kernel中拷贝到用户内存,然后kernel返回,用户进程结束block状态,重新运行。


Blocking IO的特点就是IO执行的两个阶段都是block了的。





非阻塞IO模型(non-blocking IO)[poll]


在Linux中,可以通过设置socket使其变为non-blocking,其流程如下:

image.png

  • 当用户进程调用了recvfrom这个系统调用,如果kernel中的数据还没有准备好,那么用户进程不会block而是立刻返回一个error,即从用户的角度而言,不需要等待,马上得到一个结果。


  • 从图中可以看出,用户进程在判断结果是一个error后,了解到数据还没有准备好,于是就不断重复上述操作直至kernel中的数据准备好,然后它马上将数据拷贝到了用户内存,然后返回。





多路复用IO模型(multiplexing IO)


select/epoll/evpoll,也被称作是Event-Driven IO。好处是单个process可以同时处理多个网络连接的IO。


  • 基本原理可见下面的“IO复用技术”。也叫多路IO就绪通知。


  • 这是一种进程预先告知内核的能力,让内核发现进程指定的一个或多个IO条件就绪了,就通知用户进程


  • 使得一个进程能在一连串的事件上等待。

image.png

  • 这个流程和Blocking IO的流程其实并没有太多不同,事实上仅从图中看起来,由于需要进行两次系统调用,可能更差一些。但是,Select的优势在于它可以同时处理多个连接。


  • 如果处理的连接数不是很高的话,使用“Select/Epoll 的 Web Server”不一定比使用“多线程 + BIO的Web Server”性能更好,反而延迟会更大。



Select/Epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。


在IO多路复用模型中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。




异步IO(asynchronous IO)


用户进程发起read操作之后,立刻就可以开始去做其它的事。


image.png


  1. 从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block


  1. kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了



比较


image.png


非阻塞和异步的区别


经过上面的介绍,会发现non-blocking IO和asynchronous IO的区别还是很明显的。


  • 在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。


  • asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。




IO复用技术


在IO编程过程中,当需要处理多个请求时,可以使用多线程和IO复的方式进行处理。



IO复用是什么?


把多个IO的阻塞复用到一个select之类的阻塞上,从而使得系统在单线程的情况下同时支持处理多个请求


IO复用常见的应用场景:


  • 服务器需要同时处理多个处于监听状态和多个连接状态的套接字;


  • 服务器需要处理多种网络协议的套接字


  • IO复用的实现方式目前主要有select、poll和epoll/evpoll。


select和poll的原理基本相同:


  1. 注册待侦听的fd(这里的fd创建时最好使用非阻塞)


  1. 每次调用都去检查这些fd的状态,当有一个或者多个fd就绪的时候返回


  1. 返回结果中包括已就绪和未就绪的fd



select和poll与epoll机制的比较


Linux网络编程过程中,相比于select/poll,epoll是有着更明显优势的一种选择


  • 支持一个进程打开的socket描述符不受限制(仅受限于操作系统的最大文件句柄数 unlimit)。


  • Select的缺陷:一个进程所打开的FD受限,默认是2048;尽管数值可以更改,但同样可能导致网络效率下降;可以选择多进程的解决方案,但是进程的创建本身代价不小,而且进程间数据同步远比不上线程间同步的高效。


  • epoll所支持的FD上限是最大可以打开文件的数目:/proc/sys/fs/file-max


IO效率可能随着文件描述符数目的增加而线性下降。


  • epoll扫描系统的机制不同


  • select/poll是线性扫描FD的集合


  • epoll是根据FD上面的回调函数实现的,活跃的socket会主动去调用该回调函数,其它socket则不会,相当于市是一个AIO,只不过推动力在OS内核。


  • 使用mmap加速内核与用户空间的消息传递,zero-copy的一种


  • epoll的API更加简单


  • IO复用还有一个 水平触发 和 边缘触发 的概念:


  • 水平触发:当就绪的fd未被用户进程处理后,下一次查询依旧会返回,这是select和poll的触发方式。


  • 边缘触发:无论就绪的fd是否被处理,下一次不再返回。理论上性能更高,但是实现相当复杂,并且任何意外的丢失事件都会造成请求处理错误。epoll默认使用水平触发,通过相应选项可以使用边缘触发。





IO模型的总结


最后,再举几个不是很恰当的例子来说明这四个IO Model,有A,B,C,D四个人在钓鱼:


  • A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆;(同步阻塞)


  • B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆;(非阻塞)


  • C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来;(io多路复用机制)


  • D是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。(异步机制)












相关文章
|
12天前
|
存储 安全 网络安全
云计算与网络安全:技术融合的未来之路
【10月更文挑战第30天】在数字化浪潮的推动下,云计算已成为企业信息技术架构的核心。然而,随之而来的网络安全问题也日益凸显。本文将探讨云计算与网络安全的关系,分析云服务中的安全挑战,并提出相应的解决方案。我们将通过实例展示如何在云计算环境中实现网络安全的最佳实践,以期为读者提供一条技术融合的未来之路。
|
3天前
|
云安全 安全 网络安全
云计算与网络安全:技术挑战与解决策略
【10月更文挑战第39天】随着云计算技术的飞速发展,网络安全问题也日益凸显。本文将探讨云计算环境下的网络安全挑战,并提出相应的解决策略。通过分析云服务模型、网络安全威胁以及信息安全技术的应用,我们将揭示如何构建一个安全的云计算环境。
|
3天前
|
存储 网络协议 安全
30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场
本文精选了 30 道初级网络工程师面试题,涵盖 OSI 模型、TCP/IP 协议栈、IP 地址、子网掩码、VLAN、STP、DHCP、DNS、防火墙、NAT、VPN 等基础知识和技术,帮助小白们充分准备面试,顺利踏入职场。
13 2
|
4天前
|
云安全 安全 网络安全
云计算与网络安全:技术融合的未来之路
【10月更文挑战第38天】 在数字化浪潮中,云计算和网络安全成为支撑现代企业和个人数据安全的两大基石。本文将深入探讨云计算服务如何与网络安全技术相结合,保障信息安全,并分析面临的挑战及未来发展趋势。我们将通过实际案例,揭示云安全的最佳实践,为读者提供一条清晰的技术融合路径。
|
5天前
|
安全 网络安全 数据库
云计算与网络安全:技术融合的未来之路
【10月更文挑战第37天】本文将探讨云计算与网络安全的交汇点,揭示它们如何共同塑造信息安全的未来。我们将深入了解云服务的核心组件、网络安全的关键策略以及两者如何相互增强。通过分析当前的挑战和未来的趋势,本文旨在为读者提供一条清晰的路径,以理解并应对这一不断发展的技术领域。
|
6天前
|
网络协议 数据挖掘 5G
适用于金融和交易应用的低延迟网络:技术、架构与应用
适用于金融和交易应用的低延迟网络:技术、架构与应用
31 5
|
4天前
|
运维 网络协议 算法
7 层 OSI 参考模型:详解网络通信的层次结构
7 层 OSI 参考模型:详解网络通信的层次结构
13 1
|
7天前
|
存储 安全 网络安全
云计算与网络安全:技术融合与挑战
【10月更文挑战第35天】本文将探讨云计算与网络安全的交叉点,包括云服务、网络安全和信息安全等技术领域。我们将深入了解云计算的基本概念,以及如何通过云服务实现网络安全和信息安全。同时,我们还将讨论云计算面临的安全挑战,并提出相应的解决方案。最后,我们将通过代码示例展示如何在云计算环境中实现网络安全和信息安全。
22 3
|
8天前
|
存储 安全 网络安全
云计算与网络安全:云服务、网络安全、信息安全等技术领域的深度剖析
【10月更文挑战第34天】本文将深入探讨云计算与网络安全的关系,包括云服务、网络安全、信息安全等技术领域。我们将通过实例和代码示例,解析云计算如何改变网络安全的格局,以及如何在云计算环境下保护信息安全。我们将从云计算的基本概念开始,然后深入到网络安全和信息安全的主题,最后通过代码示例来展示如何在云计算环境下实现网络安全和信息安全。
|
9天前
|
供应链 安全 网络安全
区块链技术与网络安全:机遇与挑战
区块链技术与网络安全:机遇与挑战
34 2