彻底搞懂零拷贝

1 篇文章 0 订阅
1 篇文章 0 订阅

传统IO

传统IO的底层实际上是通过read()和write()来实现的

1、通过read()把数据从硬盘读取到内核缓冲区

2、从缓冲区copy到用户缓冲区

3、通过write()写入到socket缓冲区

4、从socket缓冲区写入到网卡设备

file.read(fileDesc,buf,len);
Socket.send(socket,buf,len);

此过程发生了四次用户态到内核态的上下文切换、以及4次数据的拷贝

具体流程:

1、用户通过read()方法向操作系统发起调用、此时上下文从用户态切换到内核态、DMA控制器此时把数据从硬盘区拷贝到读缓冲区

2、CPU把读缓冲区的数据copy到应用缓冲区,此时此时内核态转化成用户态,read()返回

3、用户通过write()方法发起调用,此时上下文从用户态转化成内核态

4、CPU将应用缓冲区的数据copy到socket缓冲区

5、DMA控制器把数据从socket缓冲区copy到网卡。上下文切换从内核态转成用户态,write()返回

在这里插入图片描述因此产生疑问、用户态和内核态是什么?以及上下文切换又是什么?
用户态:用户进程的运行空间。
内核态:内核的运行空间。
如果进程运行在内核空间为内核态,运行在用户空间为用户态。
用户态与内核态是相互隔离的,因此用户态与内核态的之间上下文切换也是耗时比较长的。
因此、一次简单的IO产生4次上下文切换,在高并发场景下影响性能的

DMA拷贝?
对于一个IO而言,都是通过CUP发出对应的指令完成,但是与CPU对比IO的速度就慢了很多,因此CUP大部分时间处于IO等待状态
因此产生的DMA内存直接访问技术、本质上说就是就是主板上一块独立的芯片,通过他来做内存与IO设备之间的数据传输,从而减少CPU的等待时间。
但是只要发生拷贝就会有耗时。

零拷贝

零拷贝技术是指计算机执行操作时候,CPU不需要先将数据从某个内存复制到另一个特定区域,这种技术通常用于通过网络传输文件是减少CPU周期和内存带宽。
通俗的理解,零拷贝并非是不发生拷贝,而是减少CPU拷贝的次数、用户态与内核态的上下文切换次数。
常见的零拷贝技术:

  1. mmap+write
  2. sendfile
  3. sendfile+DMA Scatter/Gather

mmap+write

使用mmap替换了read+write的read的操作,减少一次CPU的拷贝。
mmap的主要实现方式是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区与应用缓冲区共享,从而减少从读缓冲到用户缓冲的CPU一次拷贝

在这里插入图片描述
整个过程发生了四次用户态与内核态的上下文切换和3次拷贝:

  1. 用户通过mmap方法发起操作系统的调用,上下文从用户态转成内核态。
  2. DMA控制器将硬盘数据copy到读缓冲区。上下文从内核态转成用户态。mmap调用返回
  3. 用户通过write()方法发起调用,上下文从用户态转成内核态。
  4. CPU将读缓冲区的数据copy到socket缓冲区
  5. DMA控制器将socket缓冲区数据copy到网卡,上下文从内核态切换到用户态,write()返回。

mmap的方式减少了一次CPU的拷贝,同时由于用户进程中的内存是虚拟的,只是从用户缓冲区映射到读缓冲区,所以节省一半的内存空间,比较适合大文件的传输。

sendfile

对比mmap来说,sendfile同样减少一次CPU的copy,而且还减少了两次上下文切换。

sendfile 是Linux2.1的内核版本后引用的一个系统调用函数。通过使用sendfile的数据可以直接在内核空间中传输,因此,避免了用户空间到内核空间中的拷贝,同时由于使用sendfile替换read+write从而节省一次系统调用,也就是两次上下文切换。
在这里插入图片描述
因此此次过程发生了两次用户态与内核态的切换和3次copy:

  1. 用户进程通过sendfile()发起操作系统的调用,上下文从用户态切换到内核态。
  2. DMA控制器把硬盘的数据copy到读缓冲区。
  3. CPU将读缓冲区的数据copy到socket缓冲区。
  4. DMA将socket缓冲区的数据copy到网卡设备,上下文从内核态切换到用户态。sendfile()结束调用返回。

sendfile的IO数据对用户空间不可见,所以只能适用于完全不需要用户空间的处理情况。例如静态文件服务器。

sendfile+DMA Scatter/Gather

linux2.4 内核版本之后对sendfile进行了优化。通过引入新的硬件技术,这种方式叫DMA Scatter/Gather 分散和收集功能。

通过将读缓冲区的数据描述信息,内存地址和偏移量记录在socket缓冲区,由DMA,根据这些数据读缓冲区 拷贝到网卡。相比之间减少了一次CPU拷贝。
综合发现,2次上下文的用户态到内核态的切换,2次DMA的拷贝。没有了CPU的拷贝。

在这里插入图片描述

  1. 用户进程通过sendfile()发起操作系统的调用。上下文从用户态切换到内核态。
  2. DMA控制器通过Scatter把数据从硬盘拷贝到读缓冲区离散存储
  3. CPU将读缓冲区的文件描述符和数据长度发送到socket缓冲区。
  4. DMA控制器根据文件描述符和数据长度,使用Scatter和Gatter把数据从内核缓冲区拷贝到网卡。
  5. sendfile调用返回。上下文从内核态切换到用户态。

特点DMA gattter 和sendfile都是对用户空间不可见的,而且需要硬件支持。同时输入文件描述符只能是文件,但是完全没有了CPU的拷贝,极大提升了性能。

应用场景

rocketMQ和kafka都使用了零拷贝技术。
对于MQ,生产者发送数据到MQ持久化到磁盘,之后消费从MQ读取数据。

RocketMQ采用的mmap+write();
kafka持久化到磁盘采用的是mmap+write(),发送数据采用的是sendfile.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值