2、数据拷贝过程

图1、 用户空间与内核空间

一、传统方式--仅CPU参与的数据拷贝

  • 当应用程序需要读取磁盘数据时,调用 read()从用户态切换到内核态,read()这个系统调用最终由 CPU 来完成;

  • CPU 向磁盘发起 I/O 请求,磁盘收到之后开始准备数据;

  • 磁盘将数据放到磁盘缓冲区之后,向 CPU 发起 I/O 中断,报告 CPU 数据已经 Ready 了;

  • CPU 收到磁盘控制器的 I/O 中断之后,开始拷贝数据,完成之后 read()返回,再从内核态切换到用户态;

                图2、传统方式数据拷贝

二、直接内存访问(Direct Memory Access,DMA)

1、直接内存访问,指硬件设备绕开 CPU 独立直接访问内存的机制。

2、DMA 在一定程度上解放了 CPU,把之前 CPU 的杂活让硬件直接自己做了,提高了 CPU 效率。

3、DMA需要硬件支持,可以理解为操作系统为提升CPU效率,为网卡、声卡、显卡、磁盘提供的一段特殊驱动程序。

图3、DMA方式数据拷贝

图4、DMA方式数据拷贝的另一种图示 

 DMA与传统方式最主要的变化是:CPU 不再和磁盘直接交互,而是 DMA 和磁盘交互并且将数据从磁盘缓冲区拷贝到内核缓冲区。

传统方式、DMA都存在多次冗余数据拷贝和内核态 &用户态的切换

三、零拷贝(Zero-Copy)

用户空间和内核空间无cpu拷贝,我们称之为0拷贝,实现方式如下:

3.1  mmap 方式(内存映射)

mmap 是 Linux 提供的一种内存映射文件的机制,它实现了将内核中读缓冲区地址与用户空间缓冲区地址进行映射,从而实现内核缓冲区与用户缓冲区的共享。

注意:映射的文件大小最大只能为1.5G~2G,所以RocketMQ存储消息的文件大小为1G

 3.2 sendfile 方式

mmap+write 方式有一定改进,但是由系统调用引起的状态切换并没有减少。

sendfile 系统调用是在 Linux 内核 2.1 版本中被引入,它建立了两个文件之间的传输通道。应用程序只需要调用 sendfile 函数即可完成数据拷贝,减少了2次切换。

注意:由于数据不经过用户缓冲区,因此该数据无法被修改。 

3.3 sendfile+DMA 收集

Linux 2.4 内核对 sendfile 系统调用进行优化,但是需要硬件 DMA 控制器的配合。

升级后的 sendfile 将内核空间缓冲区中对应的数据描述信息(如:文件描述符(FD)、地址偏移量等信息)记录到 socket 缓冲区中。

DMA 控制器根据 socket 缓冲区中的地址和偏移量将数据从内核缓冲区拷贝到网卡中,从而省去了内核空间中仅剩 1 次 CPU 拷贝。

可以简单理解为:从内核缓冲区直接拷贝到网卡 

3.4 splice 方式

splice 系统调用是 Linux 在 2.6 版本引入的,splice 系统调用可以在内核缓冲区和 socket 缓冲区之间建立管道来传输数据,避免了两者之间的 CPU 拷贝操作。

splice不再需要硬件支持,并且不再限定于 socket 上,即可实现两个普通文件之间的数据零拷贝。

四、各种方式对比

参考:

1、一文带你,彻底了解,零拷贝Zero-Copy技术_c++_奔着腾讯去_InfoQ写作平台

2、深入剖析Linux IO原理和几种零拷贝机制的实现 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值