详解零拷贝原理

前言

总所周知,磁盘读写速度令人堪忧,特别是机械硬盘,读写速度相差内存 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() 系统调用函数。

相关推荐
Nerd Nirvana32 分钟前
软考—系统架构设计(案例 | 论文)
linux·系统架构·软件工程·软考·计算机基础
勤奋的凯尔森同学2 小时前
webmin配置终端显示样式,模仿UbuntuDesktop终端
linux·运维·服务器·ubuntu·webmin
打不了嗝 ᥬ᭄6 小时前
Linux的权限
linux
落幕6 小时前
C语言-进程
linux·运维·服务器
深度Linux6 小时前
C++程序员内功修炼——Linux C/C++编程技术汇总
linux·项目实战·c/c++
风静如云8 小时前
OpenBMC:BmcWeb定义service
linux
leoufung8 小时前
VIM FZF 安裝和使用
linux·编辑器·vim
bugtraq20219 小时前
XiaoMi Mi5(gemini) 刷入Ubuntu Touch 16.04——安卓手机刷入Linux
linux·运维·ubuntu
CodeWithMe10 小时前
[ Vim ] 常用命令 and 配置
linux·编辑器·vim
DC_BLOG10 小时前
Linux-GlusterFS进阶分布式卷
linux·运维·服务器·分布式