ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【一知半解】零值拷贝

2022-07-28 11:05:18  阅读:158  来源: 互联网

标签:sendfile DMA 缓存 数据 一知半解 mmap 拷贝 零值


传统IO

  1. 应用调用read方法向操作系统发起读数据的请求,此时由用户态切换为内核态
  2. 当系统收到读数据请求时,利用DMA控制器把数据从磁盘读取到系统缓存区中(图中2.1)
  3. 再然后CPU会把系统缓存区的数据写应用缓存区(图2.2),此时由内核态切换为用户态
  4. 应用再调用write方法通知系统进行数据的写操作,此时由用户态切换为内核态
  5. CPU把应用缓存中的数据写到系统缓存区(图2.3)
  6. 再然后就是DMA控制器再把数据从系统缓存区写到网卡缓存区上(图2.4),write方法返回,此时由内核态切换为用户态

在普通的IO拷贝时要有4次的上下文切换过程和4次的拷贝过程,在高并发的场景下对性能会产生比较大的影响。

DMA

数据在读写的过程中都需要CPU发出对应的命令来完成,因为CPU的速度比IO操作要快的多,在数据拷贝的过程中CPU不可能一直处于等待的过程,但是如果不等,CPU又不知道IO什么时候处理完,为了协调高速的CPU与低速的IO的矛盾,因此引入了DMA,DMA(Direct Memory Access)直接内存访问技术,通过它来进行内存和IO设备的数据传输。大至就是CPU给DMA发一个指令,然后DMA开始干活,然后CPU干别的活,DMA干完后告诉CPU,从而减少了CPU的等待时间。

零值拷贝

观察图可以2.1 和2.2 感觉数据在此过程做了个无用功,从内核态搬到用户态,再由用户态搬到内核态,因此提出了零值拷贝,零值拷贝不是没有拷贝,而是不再有用户态和内核态间数据拷贝过程,他的实现有mmapsendfile两种方式。

mmap

mmap (member map)内存映射,数据读取到系统缓存区后,用户态数据在系统缓存区的映射就可以完成数据的传输过程。

  1. 首先向操作系统发送一个mmap命令(上图1.1),此时由用户态切换为内核态
  2. 系统收到mmap命令后,会用DMA把数据从磁盘读到到内存的缓存区中(上图1.2)。
  3. 返回数据缓存区的一个映射mmap(上图1.3),由内核态切换到用户态
  4. 用户在发起一个write的操作(上图1.4),由用户态切换到内核态
  5. cpu再把内存缓存区中的数据拷贝到另一个缓存区上(上图1.5)
  6. DMA把数据拷贝到网卡上后返回(上图1.6),并由内核态切换到用户态

mmap的操作共有4个上下文的切换和3次的数据拷贝过程,比普通的拷贝少了一次cpu的拷贝。

sendfile

mmap的拷贝方法要先获取数据区的映射,然后有用户发起写数据的命令后,在往网卡上写,如果不需要对数据做任何处理,只是原封不动的把数据发送出去,mmap命令和write命令可以合并为一个命令,直接告诉操作系统往外发送哪个数据即可,合并后的命令就sendfile。

  1. 用户往操作系统发直sendfile的命令,此时有用户态切换到内核态
  2. 系统收到命令后,由DMA把数据从磁盘上读取到系统缓存区上
  3. 然后由cpu把读到的到数据拷贝到另一个缓存区上
  4. 再由DMA把数据写到网上上
  5. 然后返回,由内核态切换到用户态

sendfile的过程由2次上下文的切换和3次的数据拷贝过程,整个过程读到的数据对用户空间不可见,适应用静态文件服务器。

sendfile升级

在sendfile的cpu把数据从缓存区从一个地方拷贝到另一个地方,也会浪费额外的空间,能不能在往网卡上写数据时只用第一次DMA拷贝出来的数据,直接拷贝到网卡上呢?因此对sendfile再次升级,引入了DMA Scatter/Gather 分散/收集功能。

  1. 用户发起sendfile命令(上图1.1),系统收到后,由用户态 切换到内核态
  2. 调用DMA利用scatter从磁盘读取数据到缓存区离散存储(上图1.2)
  3. cpu把缓存区数据的文件描述符和数据长度发送给另一个缓存区(上图1.3)
  4. DMA在从另一个缓存区读取数据时根据文件描述符和数据长度,使用scatter/gather从缓存区中读取到网卡上(上图1.4)
  5. 返回,并有内核态切换到用户态

此过程对用户空间仍然是不可见的,而且需要硬件的支持。有2次上下文切换和2次的拷贝过程,性能在大幅的提高。

场景

kafka和rocketmq都用到了mmap技术,两个中间件都有消息的持久化过程,和消息的读取过程。

mq对消息持久化和读取的过程都用到了mmap+write,而kafka则是持久化的过程用到了mmap+write,读取消息用的sendfile。

总结

为什么需要DMA?

DMA是为了解决高速CPU和低速IO操作的矛盾,cpu发起一个读取指令后,由dma接管数据的读取复制工作,cpu处理别的事件。

传统IO与零值拷贝有比较

名称 过程 上下文切换次数 拷贝次数
传统IO 读取命令、从磁盘读、写到缓存、写到用户缓存区、写到缓存区,写到网卡 4 4
mmap+write mmap命令,从磁盘读,写到缓存、返回mmap、发起write命令,从缓存读,写到另一缓存,写到网卡 4 3
sendfile sendfile命令,从磁盘读,写缓存区,写到另一缓存区,写网卡 2 3
sendfile升级版 sendfile命令,从磁盘读,写缓存区,根据文件描述符从缓存区读,写网卡 2 2


标签:sendfile,DMA,缓存,数据,一知半解,mmap,拷贝,零值
来源: https://www.cnblogs.com/hitechr/p/16527805.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有