解析从Linux零拷贝深入了解Linux-I/O(下)

文章探讨了在大文件传输场景下,零拷贝技术并非最优选择,因为它会占用PageCache,影响小文件的性能。异步I/O结合directI/O成为更好的选择,但directI/O有地址对齐和平台兼容性问题。文章还提到了NFS协议下O_DIRECT的特殊性,并展示了在Golang中实现directI/O的示例。最后,文章提及了内核缓冲区和用户缓冲区之间的优化,如Copy-on-Write技术。
摘要由CSDN通过智能技术生成

接上文解析从Linux零拷贝深入了解Linux-I/O(上)

大文件传输场景

零拷贝还是最优选吗

在大文件传输的场景下,零拷贝技术并不是最优选择;因为在零拷贝的任何一种实现中,都会有「DMA 将数据从磁盘拷贝到内核缓存区——Page Cache」这一步,但是,在传输大文件(GB 级别的文件)的时候,PageCache 会不起作用,那就白白浪费 DMA 多做的一次数据拷贝,造成性能的降低,即使使用了 PageCache 的零拷贝也会损失性能。

这是因为在大文件传输场景下,每当用户访问这些大文件的时候,内核就会把它们载入 PageCache 中,PageCache 空间很快被这些大文件占满;且由于文件太大,可能某些部分的文件数据被再次访问的概率比较低,这样就会带来 2 个问题:

  • PageCache 由于长时间被大文件占据,其他「热点」的小文件可能就无法充分使用到 PageCache,于是这样磁盘读写的性能就会下降了;

  • PageCache 中的大文件数据,由于没有享受到缓存带来的好处,但却耗费 DMA 多拷贝到 PageCache 一次。

异步 I/O +direct I/O

那么大文件传输场景下我们该选择什么方案呢?让我们先来回顾一下我们在文章开头介绍 DMA 时最早提到过的同步 I/O:

这里的同步 体现在当进程调用 read 方法读取文件时,进程实际上会阻塞在 read 方法调用,因为要等待磁盘数据的返回,并且我们当然不希望进程在读取大文件时被阻塞,对于阻塞的问题,可以用异步 I/O 来解决,即:

它把读操作分为两部分:

  • 前半部分,内核向磁盘发起读请求,但是可以不等待数据就位就返回 ,于是进程此时可以处理其他任务;

  • 后半部分,当内核将磁盘中的数据拷贝到进程缓冲区后,进程将接收到内核的通知 ,再去处理数据;

而且,我们可以发现,异步 I/O 并没有涉及到 PageCache;使用异步 I/O 就意味着要绕开 PageCache,因为填充 PageCache 的过程在内核中必须阻塞。

所以异步 I/O 中使用的是direct I/O(对比使用 PageCache 的buffer I/O),这样才能不阻塞进程,立即返回。

direct I/O 应用场景常见的两种:

  • 应用程序已经实现了磁盘数据的缓存,那么可以不需要 PageCache 再次缓存,减少额外的性能损耗。在 MySQL 数据库中,可以通过参数设置开启direct I/O,默认是不开启;

  • 传输大文件的时候,由于大文件难以命中 PageCache 缓存,而且会占满 PageCache 导致「热点」文件无法充分利用缓存,从而增大了性能开销,因此,这时应该使用`direct I/O;;

当然,由于direct I/O 绕过了 PageCache,就无法享受内核的这两点的优化:

  • 内核的 I/O 调度算法会缓存尽可能多的 I/O 请求在 PageCache 中,最后「合并 」成一个更大的 I/O 请求再发给磁盘,这样做是为了减少磁盘的寻址操作;

  • 内核也会「预读 」后续的 I/O 请求放在 PageCache 中,一样是为了减少对磁盘的操作;

实际应用中也有类似的配置,在 nginx 中,我们可以用如下配置,来根据文件的大小来使用不同的方式传输:

location /video/ { sendfile on; aio on; directio 1024m; }

当文件大小大于 direc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值