愿打开此篇对你有所帮助。
(图片来源网络)
文章目录
- 曾经的 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,我选择临时起个线程。