零拷贝技术 与 sendfile

2021-10-18 11:24:30 浏览数 (1)

愿打开此篇对你有所帮助。

(图片来源网络)

文章目录

    • 曾经的 I/O 过程
      • 弊端分析
    • 解决方案
      • 弊端
    • 解决方案
    • 现成应用场景
    • 危险!!!
    • 解决方案

曾经的 I/O 过程

弊端分析

可以看到,整个数据的传输过程,都要需要 CPU 亲自参与搬运数据的过程,而且这个过程,CPU 是不能做其他事情的。


解决方案

DMA 技术,也就是直接内存访问(Direct Memory Access) 技术。

在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。


弊端

四次上下文切换 四次拷贝。

我就传一份数据,整这么麻烦。


解决方案

在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile(),函数形式如下:

代码语言:javascript复制
#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

如果网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术,我们可以进一步减少通过 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程。

检查一下,这一步我来讲,不要去百度了,一个抄一个,都没有亲测,看着就烦。

注意看你的网卡叫什么名字,不一定就 eth0.

于是,从 Linux 内核 2.4 版本开始起,对于支持网卡支持 SG-DMA 技术的情况下, sendfile() 系统调用的过程发生了点变化。

这就是所谓的零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。


现成应用场景

1、卡夫卡 2、nginx(我就是从nginx源码里看到sendfile,于是写了这一篇)


危险!!!

在传输大文件(GB 级别的文件)的时候,PageCache 会不起作用,那就白白浪费 DMA 多做的一次数据拷贝,造成性能的降低,即使使用了 PageCache 的零拷贝也会损失性能。

由于文件太大,可能某些部分的文件数据被再次访问的概率比较低,这样就会带来 2 个问题:

代码语言:javascript复制
PageCache 由于长时间被大文件占据,其他「热点」的小文件可能就无法充分使用到 PageCache,于是这样磁盘读写的性能就会下降了;
PageCache 中的大文件数据,由于没有享受到缓存带来的好处,但却耗费 DMA 多拷贝到 PageCache 一次;

所以,针对大文件的传输,不应该使用 PageCache,也就是说不应该使用零拷贝技术,因为可能由于 PageCache 被大文件占据,而导致「热点」小文件无法利用到 PageCache,这样在高并发的环境下,会带来严重的性能问题。


解决方案

在高并发的场景下,针对大文件的传输的方式,应该使用「异步 I/O 直接 I/O」来替代零拷贝技术。

如果不是高并发的大文件IO,我选择临时起个线程。

0 人点赞