[操作系统] 减少IO拷贝的方式

参考文章:https://mp.weixin.qq.com/s/xej6klx2q0G1fp82_vKCOg

减少IO拷贝的目的是将数据直接从IO源(外存等)直接读取到目标(内存、网卡等)位置,而尽量减少在内存中的复制拷贝(通常是由于系统缓存IO机制带来的问题)。

主要思路有三种:

1. 用户态直接IO,即将数据直接IO读取到用户空间,不经过内核空间。

2. 减少拷贝次数,避免数据在缓冲区间拷贝等。

3. 写时复制技术,多个进程共享同一块数据时,不立即复制数据到新的内存块,耳式当某个进程对数据进行修改后再执行拷贝操作。

1. 用户态直接IO

在IO模式中已有详细讲述,此处不再赘述。其有点在于可以跳过内核空间,缺点在于CPU和磁盘IO有速率差距,需要配合异步IO使用。

2. mmap+write

将内核中的读缓冲区与用户空间的缓冲区直接进行映射,省去了从内核缓冲区读取数据到用户缓冲区的步骤。(注意:这样仍然会有用户态/内核态切换消耗)

这种方式通常用在处理大文件上,对于小文件时会造成内存浪费(由于内存映射需要对其页边界,最小单位为4KB,不是4KB的整数倍会导致浪费空间)。

3. SendFile

用以在讷河空间内部进行IO传输,一般针对不同外设传输数据的情况。

设想从磁盘读取数据拷贝到socket缓冲区进行发送的情景。

若是普通情况,那么数据流为:磁盘->内核缓冲区->用户缓冲区->socket缓冲区->网卡

使用SendFile会跳过用户空间:磁盘->内核缓冲区->socket缓冲区->网卡

4. SendFile + DMA gather copy

针对SendFile机制的改进,避免将数据拷贝到socket缓冲区,而是将传冲去文件描述符和数据长度拷贝过去,将socket地址映射到内核缓冲区,使得DMA直接从内核缓冲区拷贝数据到网卡。

数据流程为:磁盘->内核缓冲区->网卡

5. Splice

在讷河缓冲区和网络缓冲区间建立管道,避免执行CPU拷贝操作。其文件描述符参数中必须有一个是管道设备。

6. 写时复制(Copy-On-Write)

当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么就需要将其拷贝到自己的进程地址空间中。

7. 缓冲区共享

所有进程维护同一个缓冲区池,该缓冲区池可被映射到用户空间或者内核空间。

 

补充:

RocketMQ采用了mmap+write,适用于业务及消息(小块文件)。

Kafka采用了SendFile,适用于系统日志消息(高吞吐量大块文件)。

posted @ 2021-10-21 22:25  Cheung-10  阅读(10)  评论(0)    收藏  举报