启用 sendfile 时,Nginx 因跳过 stat 校验而读取 NFS 客户端缓存的旧元数据,导致静态资源更新延迟;解决方法为关闭 sendfile 或收紧 NFS 属性缓存(如 acregmin=1)并调优 open_file_cache。

启用 sendfile 时,Nginx 直接通过内核 zero-copy 将文件从磁盘(或挂载点)送入网络协议栈,绕过用户态缓冲。当后端是 NFS 等网络文件系统时,这一机制会与 NFS 客户端缓存、服务端元数据一致性产生冲突,导致用户看到旧内容——这不是 Nginx 缓存没刷新,而是 sendfile 读取了 NFS 客户端缓存中“尚未更新”的文件数据。
确认 sendfile 是否触发了问题
现象典型表现:
- 静态资源(如 JS/CSS/图片)在 NFS 上已更新,但浏览器仍加载旧版本,
curl -I查看Last-Modified或ETag也未变化 -
stat /path/on/nfs/file.js显示 mtime 已更新,但 Nginx 响应头中Last-Modified仍是旧时间 - 关闭
sendfile on;后问题立即消失,重启 Nginx 即可生效
根本原因:NFS 属性缓存 + sendfile 跳过 stat 校验
Nginx 在启用 sendfile 时,默认不主动调用 stat() 获取文件最新元数据(如 mtime),而是依赖内核 VFS 层返回的缓存视图。而 NFS 客户端默认开启属性缓存(attribute cache),例如:
- NFSv3 默认
acregmin=3/acregmax=60(普通文件属性缓存 3–60 秒) - NFSv4 默认更激进,可能长达数秒甚至分钟
- 这意味着即使服务端文件已改,Nginx 通过
sendfile读取的仍是客户端本地缓存的旧 inode 信息
解决路径:禁用 sendfile 或打破 NFS 缓存僵局
两种思路,按场景选择:
-
稳妥方案(推荐):关闭 sendfile
在对应location或全局配置中设sendfile off;,让 Nginx 回到常规 read/write 流程。此时每次响应前会真实调用stat(),受 NFSactimeo=1等参数控制,可实现秒级感知变更 -
性能优先方案:收紧 NFS 属性缓存 + 强制同步
在/etc/fstab挂载选项中加入:nfsvers=4.1,hard,intr,rsize=1048576,wsize=1048576,ac,acregmin=1,acregmax=1,acdirmin=1,acdirmax=1
并确保服务端导出支持快速元数据响应(如 NFSv4 delegation、SSD 存储) -
辅助验证项
添加add_header X-File-Mtime $sent_http_last_modified;,配合curl -I对比服务端stat输出,确认是否一致
延伸注意:open_file_cache 会加剧该问题
若同时启用了 open_file_cache(常见于高并发静态服务),它会缓存文件句柄和元数据,进一步掩盖 NFS 的真实变更。此时需同步调整:
- 设
open_file_cache_valid 1s;(而非默认 60s) - 禁用
open_file_cache_errors off;避免错误缓存干扰判断 - 搭配
open_file_cache_min_uses 1;减少冗余缓存











