pro*_*ark 5 linux apache nfs nginx sendfile
Apache 文档包含以下 EnableSendfile 语句:
使用网络安装的 DocumentRoot(例如,NFS、SMB、CIFS、FUSE),内核可能无法通过自己的缓存为网络文件提供服务。[1]
Apache 2.4 和 Nginx 的默认配置禁用了 sendfile()。
我试图找到一些具体的东西来描述在 Linux 上将 sendfile() 与 NFS 文件系统一起使用时的确切问题。在内核 3.10.0-327.36.3 (CentOS 7) 上运行一个最小的测试程序验证 sendfile() 在源位于 NFS 上时确实有效,并且它确实从页面缓存中读取(第一次运行很慢,随后很快, drop_caches 使其再次变慢,即从源重新读取)。我尝试使用高达 1G 的文件大小,一切似乎都正常。我假设一定有一些情况可以揭示错误行为,但我想确切地知道那是什么。
为了进行比较,有一些关于 VirtualBox 卷在 sendfile()[2] 中存在的问题的文档,但我找不到类似的内容涵盖 Apache,或者如何复制有问题的配置。
Nginx 的默认配置打开sendfile
- https://github.com/nginx/nginx/blob/release-1.13.8/conf/nginx.conf#L27所以我对你在那里的陈述感到困惑。
早在 2000 年代初期,您就可以看到一个Apache 开发人员介绍了禁用 SendFile 的选项(这里是补丁的邮件列表帖子)。还有一些旧的错误可能与 Apache 错误跟踪器中的 sendfile 相关。从Apache 错误 #12893我们了解到,其中一个失败是因为 Linux 内核中的 NTFS 实现根本不支持sendfile
系统调用:
[...] 显然,您的 NTFS 文件系统的某些特征会阻止 sendfile() 工作。
Run Code Online (Sandbox Code Playgroud)sendfile(8, 9, [0], 9804) = -1 EINVAL (Invalid argument)
一个博客文章题为“SENDFILE和Apache的神秘案件”引用您正在阅读提出了以下理论计算器问题:
sendfile() 最多传输 0x7ffff000 (2,147,479,552) 个字节,返回实际传输的字节数。(在 32 位和 64 位系统上都是如此。)
有 2GB 的限制。现在这是假设,apache 文档说:
使用网络安装的 DocumentRoot(例如,NFS、SMB、CIFS、FUSE),内核可能无法通过自己的缓存提供网络文件 [2]
因此,当它说“内核可能无法提供文件”时,我认为我们在这里可能指的是 sendfile 对文件大小的固有限制。
有趣的理论,但我怀疑这是答案,因为您可以简单地选择不对太大的文件使用 sendfile 代码路径。更新:在四处挖掘时,我发现那篇文章的作者创建了一个后续文章,标题为我错了关于 Sendfile() 和 Apache,其中提到了您正在阅读的答案!
ProFTPD 文档中也有关于 sendfile 问题的警告:
在某些情况下,文件系统而不是内核似乎是 sendfile(2) 问题的罪魁祸首:
- 网络文件系统(例如 NFS、SMBFS/Samba、CIFS)
- 虚拟化文件系统(OpenVZ、VMware,甚至 Veritas)
- 其他文件系统(例如 Linux 上的 NTFS 和 tmpfs)
同样,如果您在从 ProFTPD 下载文件时遇到问题,而这些文件驻留在网络或虚拟化文件系统上,请尝试在您的 proftpd.conf 中使用“UseSendfile off”。
很多“这里有龙”警告。其中一些是因为文件系统根本不支持 sendfile (例如,直到 2.4.22-pre3 Linux 的 tmpfs 不支持 sendfile)。基于 FUSE 的文件系统(例如 NTFS-3g)在过去也会由于 FUSE 和 sendfile 错误(因为已解决)而出现问题。不过,虚拟化文件系统的列表是一个有趣的补充……
然而,OrangeFS FAQ似乎有最合理的解释:
5.16 我们可以运行 Apache 网络服务器来从 orangefs 卷中提供文件吗?
你当然可以!但是,我们建议您在启动 Web 服务器之前关闭 httpd.conf 中的 EnableSendfile 选项。或者,您可以使用选项 -enable-kernel-sendfile 配置 orangefs。传递此选项以在支持 sendfile 回调的 orangefs 内核模块中配置结果。但我们建议,除非提供的文件足够大,否则就性能而言这可能不是一个好主意。Apache 2.x+ 使用sendfile 系统调用,通常通过 page-cache 暂存文件数据。在最近的2.6 内核上,这可以通过在文件系统中提供 sendfile 回调例程来避免. 因此,这可确保我们最终不会在此类内核上获得陈旧或不一致的缓存数据。但是,在较旧的 2.4 内核上,sendfile 系统调用通过页面缓存流式传输数据,因此数据很有可能过时。因此,sendfile 系统调用的用户被警告要小心这个细节。
类似的解释可以在Linux guest readv system call returns stale (cached) shared folder file data Virtualbox bug 中阅读:
我发现使用 read 系统调用读取文件的程序返回正确的数据,但那些使用 readv 系统调用的程序(例如我的 gas 版本)读取过时的缓存数据。
[...]
使用核函数 generic_file_read_iter 作为 file_operations 结构的 .read_iter 成员(.read_iter 在执行 readv 系统调用时使用)。此函数将写入和读取文件缓存。但是,用于通用 .read 成员和 read 系统调用的 vbox 函数 sf_reg_read 似乎总是绕过 Linux 的 FS 缓存。
[...]
此外,我认为类似的长期问题报告为票证#819,仅适用于 sendfile 系统调用。似乎所有这些 generic_file_* 函数都期望主机控制对驱动器的所有访问。
以上也可以解释 ProFTPD 的问题虚拟化文件系统列表。
Apache 建议不要sendfile()
与 Linux NFS 一起使用,因为他们的软件很流行,并且在sendfile
使用旧的 Linux NFS 客户端调试相关错误时会引发许多痛苦的事情。警告是旧的,保持原样可能更容易,而不是用所有警告更新它。
如果您有一个 Linux 文件系统,其中可以在不使 Linux 页面缓存失效的情况下更改底层数据sendfile
,那么在旧的 Linux 内核上使用它是不明智的(这解释了旧的 Linux NFS 客户端问题)。对于较新的内核,如果上述文件系统没有实现自己的sendfile
钩子,再次使用sendfile
是不明智的(Virtualbox 共享文件夹问题证明了这一点)。
最近的(2.6.31 及更高版本)Linux 内核为可能面临此失效问题的文件系统提供了使用自己的sendfile
实现的工具,并假设文件系统可以使用它来sendfile
阻止错误,但请注意空客!
归档时间: |
|
查看次数: |
2551 次 |
最近记录: |