一文搞懂网络通信的基石✅IO模型与零拷贝

简介: 【10月更文挑战第1天】本文深入探讨了网络通信中的IO模型及其优化方法——零拷贝技术。首先介绍了IO模型的概念及五种常见类型:同步阻塞、同步非阻塞、多路复用、信号驱动和异步IO模型。文章详细分析了每种模型的特点和适用场景,特别是多路复用和异步IO在高并发场景中的优势。接着介绍了零拷贝技术,通过DMA直接进行数据传输,避免了多次CPU拷贝,进一步提升了效率。最后总结了各种模型的优缺点,并提供了相关的代码示例和资源链接。

网络通信的基石:IO模型与零拷贝

中间件作为现代软件架构的基石,扮演着承上启下的关键角色,它不仅衔接了多样化的服务与系统,还极大地促进数据的流动与处理

而这一切高效运作的背后,网络通信是各大中间件中不可或缺的一环

如常见的WEB服务器(tomcat、jetty、undertow),数据库(MySQL、Redis),MQ...

它们都需要进行网络通信,那么如何才能高效的进行网络通信呢?

在聊这个话题前,我们需要先聊聊IO模型

什么是IO模型呢?

IO即输入/输出,IO模型的提出主要是解决计算机CPU在内存与磁盘/网卡等外部设备速度不匹配的问题

当CPU想要读取磁盘/网卡上的数据时,数据拷贝到内存是需要时间的,那这时CPU是去等待数据拷贝完成,还是先去执行其他任务呢?

举个简单的例子:

精通CRUD的小菜快速完成简单的CRUD,但还需要等待其他部门提供的接口,由于其他部门的业务比较复杂,接口文档可能要几天后才能给出,小菜想趁着这段时间休息一会

可是作为小菜上司的我可不乐意了,还有这么多开发任务呢,我再分一个任务给小菜做,让小菜不能空闲下来,等到后续其他部门的接口写好了,再通知小菜完成这个开发任务(提升小菜的“吞吐量”)

这个案例中小菜就是CPU,完成简单的CRUD可以看成在内存上操作(速度快),等待其他部门的接口可以看成等待外部设备把数据拷贝到内存(速度慢)

为了解决这个问题,我提出一种“IO模型”:让小菜先去干别的活,等其他部门的接口好了再通知小菜回来完成这个开发任务

步入正题,常见的IO模型分为五种:同步阻塞IO模型、同步非阻塞IO模型、多路复用IO模型、信号驱动IO模型、异步IO模型

处理流程

为了更好的理解IO模型,先举个体现总体流程的下载文件案例:

下载文件案例中,客户端先向服务端发送请求,而服务器收到请求后,读取磁盘中的文件数据,发送到网卡上再响应给客户端

在这个过程中,以服务端的视角可以看成先从磁盘中读取数据,再往网卡上写数据

由于磁盘、网卡属于外部设备,由于外部设备速度慢,不会使用CPU进行拷贝数据,而是通过DMA进行数据拷贝(这样就不需要占用CPU的资源)

操作系统分为用户态和内核态,其中应用程序处于用户态

由于操作系统中的重要资源不能被用户态的应用程序直接访问,需要先切换到内核态再进行访问

image.png

用传统的阻塞IO(BIO)举例,当服务端接收到请求后:

  1. 读取磁盘要先切换为内核态,然后由DMA进行拷贝(将磁盘上的数据拷贝到内核缓冲区),此时用户线程一直阻塞
  2. DMA拷贝完成后,由CPU将数据从内核缓冲区拷贝到用户态内存上的用户缓冲区,此时用户线程才被唤醒
  3. 状态切换为用户态后,用户线程从用户态中内存的缓冲区将数据拷贝到JVM的堆内存缓冲区中
  4. Java程序处理数据(已经读完),开始写数据,写数据的流程与读数据流程类似,只不过是相反的

图中的直接内存为用户态的内存,而堆内存为JVM的(属于JVM管理)

在这个过程中:用户线程一直阻塞,读数据与写数据存在大量重复拷贝、状态切换,都会导致性能被大大浪费

通过IO模型、零拷贝等优化方式能够优化这个过程,提升响应速度

IO模型

同步阻塞

在同步阻塞IO模型下,当用户线程请求读取外部设备的数据时,会一直阻塞直到数据拷贝完成,再去使用数据

image.png

具体流程如下:

  1. 用户线程发起系统调用请求读取外部设备数据(进入阻塞)
  2. 用户态切换为内核态准备数据:使用DMA将外部设备数据拷贝到内核缓冲区
  3. 内核进行数据拷贝:将内核缓冲区的数据拷贝到用户缓冲区
  4. 内核态切换为用户态,使用数据

阻塞指的是:在用户线程发起系统调用时,并没有立即返回,而是等到数据拷贝完成被唤醒再使用

同步指的是:在数据拷贝阶段,用户线程是阻塞等待数据完成拷贝的(也可以理解为同步是用户线程主动请求内核进行数据拷贝的)

在同步阻塞IO模型下,由于准备、拷贝数据阶段都会阻塞等待,因此性能并不理想

如果高并发的请求打进来,让等比例的线程数量来等待,资源开销是非常大的,因此现代中间件一般不会采取这种模型

同步非阻塞

同步非阻塞IO模型会频繁发起系统调用来判断数据是否已就绪,如果已就绪则同步阻塞进行拷贝

在这个过程中,准备数据阶段是通过轮询非阻塞的方式实现的,当响应数据就绪时,再发起系统调用同步阻塞进行数据拷贝

image.png

同步非阻塞IO模型虽然在数据准备的阶段不需要阻塞,但会通过轮询的方式一直进行系统调用,产生一定的开销

要求网络通信高效的中间件也不会使用这种模型

多路复用

在多路复用模型中,内核线程能够同时监听多个网络请求的通道

使用前,会将数据通道注册到select上,当使用select时会进行阻塞,直到select监听到数据通道上数据已就绪,此时再请求读取数据,使用read系统调用,同步阻塞直到拷贝完数据

image.png

在多路复用模型中实现还分为三种方式:select、poll、epoll

select就是上述举例流程,缺点是最多监听1024个数据通道,并且阻塞到数据就绪时需要遍历处理O(n)

poll在select基础上,动态调整只要内存够理论上无监听通道数量的上限,但数据就绪时还需要遍历处理

epoll使用事件回调的方式,当数据就绪时不需要再轮询,并且内核维护不再需要将数据拷贝到用户态

在多路复用模型中,由于一个内核线程可以监听多个数据通道,这样即使维护大量的网络数据通道,开销也不会太大

而且有epoll事件回调、不用拷贝的优化性能非常好,大部分的中间件都会选择多路复用模型实现网络通信

信号驱动

在信号驱动模型中,会先发送信号的系统调用(立即返回 非阻塞),当数据准备好后通知,再发送读数据的系统调用(阻塞),让内核完成拷贝数据

image.png

信号驱动避免准备数据时的阻塞,并且不需要轮询发起系统调用,但在数据拷贝时依旧需要同步阻塞

异步

在异步IO模型中,发起请求的系统调用时会携带回调函数,发起系统调用后立即返回(非阻塞)

当数据就绪后,不需要用户线程同步触发,而是由内核主动将数据拷贝到用户缓冲区

image.png

在异步IO(AIO)中完全没有阻塞也不再需要同步

在要求高效的高并发网络通信中,一般使用多路复用模型NIO和异步IO(AIO)

JDK中的NIO指的就是多路复用模型,而NIO2指的就是AIO,后续讲解中间件如何高效处理网络通信时都会出现它们的身影~

零拷贝

聊完IO模型后,我们能够知道使用NIO、AIO能够加快处理流程的速度

处理流程中还存在大量的CPU拷贝,在Linux内核逐步升级后,网卡支持的情况下还可以实现零拷贝

零拷贝指的是不再需要使用CPU进行数据拷贝,而是直接通过DMA进行拷贝

image.png

为什么无法从内核直接拷贝到JVM堆内存?

在传统的流程处理中,需要先从内核拷贝到直接内存,再从直接内存拷贝到JVM堆内存

既然直接内存和JVM堆内存都处于用户态的内存,为什么不从内核直接拷贝到JVM堆内存呢?

这是由于JVM堆内存会发生GC,可能改变位置,内核拷贝到堆内存时无法保证不会GC

而本地内存拷贝到JVM堆内存,HotSpot虚拟机保证不在安全点上,因此不会GC

JVM安全点相关知识感兴趣的同学可以查看这篇文章

总结

IO模型的提出是为了解决CPU在内存的速度与外部设备加载到内存速度的差异

在操作系统中为了安全使用系统资源,IO时会涉及到用户态、内核态的切换

IO阶段通常分为准备数据和拷贝数据,准备数据主要由DMA将外部设备数据拷贝到内核缓冲区,拷贝数据是将内核缓冲区拷贝到用户缓冲区

同步阻塞IO模型(BIO)发起系统调用后会阻塞到数据拷贝完成,不适合处理高并发网络通信的场景

同步非阻塞IO模型使用轮询的方式判断数据是否就绪,就绪再同步阻塞等待数据拷贝

信号驱动模型中数据就绪后通过信号通知应用发起系统调用读取数据,避免同步非阻塞下轮询的开销

多路复用IO模型使用select时,监听多个通道,select阻塞直到监听到通道上数据就绪,再通知应用进行读取发起同步阻塞直到数据拷贝结束

使用select,当多个通道数据同时就绪时,只能轮询处理,并且只能监听1024个通道;使用poll进行优化能够监听无上限通道数量

使用epoll 事件回调的方式避免轮询处理,并且内核维护不需要再进行数据拷贝

异步IO模型使用回调的方式避免数据就绪时同步阻塞进行数据拷贝,Linux下也是使用epoll模拟实现

当网卡支持时使用sendfile零拷贝可以避免大量CPU数据拷贝

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 后端的网络基石,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 Gitee-CaiCaiJavaGithub-CaiCaiJava,除此之外还有更多Java进阶相关知识,感兴趣的同学可以starred持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多技术干货,公众号:菜菜的后端私房菜

相关文章
|
2月前
|
域名解析 网络协议 安全
计算机网络TCP/IP四层模型
本文介绍了TCP/IP模型的四层结构及其与OSI模型的对比。网络接口层负责物理网络接口,处理MAC地址和帧传输;网络层管理IP地址和路由选择,确保数据包准确送达;传输层提供端到端通信,支持可靠(TCP)或不可靠(UDP)传输;应用层直接面向用户,提供如HTTP、FTP等服务。此外,还详细描述了数据封装与解封装过程,以及两模型在层次划分上的差异。
412 13
|
2月前
|
网络协议 中间件 网络安全
计算机网络OSI七层模型
OSI模型分为七层,各层功能明确:物理层传输比特流,数据链路层负责帧传输,网络层处理数据包路由,传输层确保端到端可靠传输,会话层管理会话,表示层负责数据格式转换与加密,应用层提供网络服务。数据在传输中经过封装与解封装过程。OSI模型优点包括标准化、模块化和互操作性,但也存在复杂性高、效率较低及实用性不足的问题,在实际中TCP/IP模型更常用。
268 10
|
5月前
|
机器学习/深度学习 编解码 自动驾驶
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV1,用于移动视觉应用的高效卷积神经网络
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV1,用于移动视觉应用的高效卷积神经网络
132 3
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV1,用于移动视觉应用的高效卷积神经网络
|
5月前
|
机器学习/深度学习 移动开发 测试技术
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV2,含模型详解和完整配置步骤
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV2,含模型详解和完整配置步骤
162 1
RT-DETR改进策略【模型轻量化】| 替换骨干网络为MoblieNetV2,含模型详解和完整配置步骤
|
2月前
|
监控 应用服务中间件 Linux
掌握并发模型:深度揭露网络IO复用并发模型的原理。
总结,网络 I/O 复用并发模型通过实现非阻塞 I/O、引入 I/O 复用技术如 select、poll 和 epoll,以及采用 Reactor 模式等技巧,为多任务并发提供了有效的解决方案。这样的模型有效提高了系统资源利用率,以及保证了并发任务的高效执行。在现实中,这种模型在许多网络应用程序和分布式系统中都取得了很好的应用成果。
95 35
|
5月前
|
机器学习/深度学习 编解码 TensorFlow
RT-DETR改进策略【模型轻量化】| 替换骨干网络为EfficientNet v1 高效的移动倒置瓶颈结构
RT-DETR改进策略【模型轻量化】| 替换骨干网络为EfficientNet v1 高效的移动倒置瓶颈结构
304 0
RT-DETR改进策略【模型轻量化】| 替换骨干网络为EfficientNet v1 高效的移动倒置瓶颈结构
|
5月前
|
机器学习/深度学习 计算机视觉 异构计算
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2023 FasterNet 高效快速的部分卷积块
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2023 FasterNet 高效快速的部分卷积块
187 0
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2023 FasterNet 高效快速的部分卷积块
|
5月前
|
机器学习/深度学习 计算机视觉 iOS开发
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2024 RepViT 轻量级的Vision Transformers架构
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2024 RepViT 轻量级的Vision Transformers架构
254 0
RT-DETR改进策略【模型轻量化】| 替换骨干网络 CVPR-2024 RepViT 轻量级的Vision Transformers架构
|
2月前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现CTR模型DIN(Deep interest Netwok)网络
本文详细讲解了如何在昇腾平台上使用PyTorch训练推荐系统中的经典模型DIN(Deep Interest Network)。主要内容包括:DIN网络的创新点与架构剖析、Activation Unit和Attention模块的实现、Amazon-book数据集的介绍与预处理、模型训练过程定义及性能评估。通过实战演示,利用Amazon-book数据集训练DIN模型,最终评估其点击率预测性能。文中还提供了代码示例,帮助读者更好地理解每个步骤的实现细节。
|
5月前
|
机器学习/深度学习 自动驾驶 计算机视觉
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 GhostNet V1 基于 Ghost Module 和 Ghost Bottlenecks的轻量化网络结构
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 GhostNet V1 基于 Ghost Module 和 Ghost Bottlenecks的轻量化网络结构
238 61
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 GhostNet V1 基于 Ghost Module 和 Ghost Bottlenecks的轻量化网络结构