详解零拷贝原理

前言

总所周知,磁盘读写速度令人堪忧,特别是机械硬盘,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝、直接 I/O、异步 I/O 等等,下面我们就分几个点来讲讲零拷贝技术。

DMA技术是什么?

直接内存访问(Direct Memory Access 技术,在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务

在没有 DMA 技术前,I/O 的过程是这样的:

  • CPU发起IO指令给磁盘
  • 磁盘收到指令,把数据放入磁盘缓冲区,然后产生一个中断;
  • CPU 收到中断信号后,把磁盘缓冲区的数据读进内核缓冲区,然后再把内核缓冲区写入到用户缓冲区,而在数据传输的期间 CPU 是无法执行其他任务的

有 DMA 技术之后,I/O 的过程是这样的:

可以看到, 整个数据传输的过程,CPU 不再参与数据搬运的工作,而是全程由 DMA 完成,大大提高了CPU的性能。

传统IO

传统文件传输,将磁盘上的文件读取出来,然后通过网络协议发送给客户端。

流程: 磁盘->内核缓冲区->用户缓存区->socket缓冲区->网卡缓冲区

分析: 4次拷贝(2次DMA,2次CPU),4次状态切换,因为发生了两次系统调用,一次是 read() ,一次是 write(),每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态

结论: 想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数

  • 要想减少上下文切换到次数,就要减少系统调用的次数
  • 在用户空间我们并不会对数据「再加工」,所以数据实际上可以不用搬运到用户空间,因此用户的缓冲区是没有必要存在的

mmap内存映射

针对传统IO的缺陷,一个优化方案就是通过mmap系统替代read系统调用,这个函数的作用是让用户缓冲区共享内核缓冲区

流程: 硬盘->内核缓冲区=用户缓存区->socket缓冲区->网卡缓冲区

分析: 3次拷贝,4次状态切换,因为mmap系统调用也是2次状态切换

结论: 但这还不是最理想的零拷贝,因为仍然需要通过 CPU 把内核缓冲区的数据拷贝到 socket 缓冲区里,而且仍然需要 4 次上下文切换

sendFile

在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile(),它可以替代前面的 read()write() 这两个系统调用,这样就可以减少一次系统调用,也就减少了 2 次上下文切换的开销。

流程: 硬盘->内核缓冲区->socke缓冲区->网卡缓冲区

分析: 3次拷贝,2次状态切换,只有一次sendFile系统调用,2次状态切换

优化: linux2.4后续优化:硬盘->内核缓冲区->网卡缓冲区

2次拷贝,2次状态切换,源头到目标,零拷贝,全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的,这就是真正意义上的零拷贝

应用场景

事实上,Kafka 这个开源项目,就利用了「零拷贝」技术,从而大幅提升了 I/O 的吞吐率,这也是 Kafka 在处理海量数据为什么这么快的原因之一。

如果你追溯 Kafka 文件传输的代码,你会发现,最终它调用了 Java NIO 库里的 transferTo方法:

arduino 复制代码
@Overridepublic   
long transferFrom(FileChannel fileChannel, long position, long count) throws IOException {   
    return fileChannel.transferTo(position, count, socketChannel);  
}

如果 Linux 系统支持 sendfile() 系统调用,那么 transferTo() 实际上最后就会使用到 sendfile() 系统调用函数。

相关推荐
Betty’s Sweet11 分钟前
[Linux]:线程(三)
linux·线程·信号量·生产者消费者模型
程序员南飞2 小时前
ps aux | grep smart_webrtc这条指令代表什么意思
java·linux·ubuntu·webrtc
StrokeAce2 小时前
linux桌面软件(wps)内嵌到主窗口后的关闭问题
linux·c++·qt·wps·窗口内嵌
热爱嵌入式的小许6 小时前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风10 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学10 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO10 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu711 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我11 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、11 小时前
【Linux】进程地址空间(初步了解)
linux