
前面文章中我们探讨了 Nginx 的前端与后端(反向代理)缓存机制,并实践了在不同环境下的配置方法。在此基础之上,本章将深入讲解 Nginx 中另一个至关重要的性能优化功能——open_file_cache。它通过缓存文件句柄及其元信息(如修改时间、大小等),能够显著提升性能,尤其能够有效避免频繁的 open 和 close 操作所带来的系统调用开销,对于优化 Nginx 服务器的响应能力大有裨益。
那么,open_file_cache 究竟缓存了哪些内容?它又是如何切实提升性能的呢?接下来我们将通过详细的指令解析和一个完整的实践案例,来讲解如何配置和验证 Nginx 的 open_file_cache 功能。
简单介绍
open_file_cache 指令属于 ngx_http_core_module 模块,通常已默认编译进 Nginx,但其功能默认是关闭的。它可以缓存以下几类关键的元信息:
- 文件句柄 (fd):缓存文件句柄意味着,在文件被打开后,无需在每次请求处理完毕时都执行
close 操作,并且在后续需要时也无需重新 open。这直接减少了 open/close 系统调用的次数,是提升性能的核心。
- 文件修改时间 (mtime):缓存后,在文件被频繁访问时,Nginx 无需每次都调用
stat 系统调用来获取文件的最后修改时间。
- 文件大小 (size):同理,缓存文件大小信息也能避免频繁的
stat 调用。
- 文件查询错误信息 (err):当因权限不足等原因导致文件访问失败时,缓存的错误信息(如 403 Forbidden)可以让 Nginx 在缓存有效期内直接返回,无需重复进行失败的
open 尝试。
- 文件存在性与类型:缓存文件的“是否存在”及类型信息,同样可以减少不必要的
stat 系统调用。

open_file_cache 不仅适用于静态资源服务,还广泛用于 Nginx 自身的日志文件、缓存文件操作等场景。需要注意的是,为了保持缓存数据与磁盘文件的一致性,需要合理设置缓存超时时间,特别是在文件可能被外部进程频繁修改的环境中。
指令参数
open_file_cache 指令用于在内存中缓存已打开文件的描述符,通过限制缓存最大数量和设置非活跃淘汰时间,来减少文件打开操作的频率。
Syntax: open_file_cache off;
open_file_cache max=N [inactive=time];
Default: open_file_cache off;
Context: http, server, location
# 参数说明:
max=N 设置内存缓存的最大元素数量,默认为1024个文件描述符。当缓存数量超过此值时,会按照LRU(最近最少使用)策略,结合inactive参数进行清理。
inactive 设置缓存元素的有效期,默认为60秒。如果一个元素在此时间内未被访问,它将被从缓存中清除。
off 关闭缓存功能,等同于不配置该指令。
open_file_cache_errors 指令用于启用或禁用文件查找错误的缓存。启用后,在缓存有效期内,Nginx 会直接返回之前的错误信息,而不会重新尝试打开文件。
Syntax: open_file_cache_errors on | off;
Default: open_file_cache_errors off;
Context: http, server, location
open_file_cache_min_uses 指令用于设置一个文件在 inactive 时间段内至少需要被访问多少次,才能被保留在缓存中。这有助于筛选出真正的“热点”文件。
Syntax: open_file_cache_min_uses number;
Default: open_file_cache_min_uses 1;
Context: http, server, location
open_file_cache_valid 指令用于定期检查缓存中文件句柄的有效性。这确保了当文件被外部进程更新后,Nginx 能够获取到最新的文件信息,避免向客户端返回过时的内容。
Syntax: open_file_cache_valid time;
Default: open_file_cache_valid 60s;
Context: http, server, location
以下是 Nginx 官方文档中给出的一个配置示例,清晰地展示了如何组合使用这些指令:
Example:
# 开启缓存,最大缓存1000个文件描述符,在60秒内未被访问将被移除
open_file_cache max=1000 inactive=60s;
# 每30秒检查一次缓存文件句柄的有效性,确保获取最新的文件信息
open_file_cache_valid 30s;
# 文件在60秒内最少被访问2次后才会被加入缓存
open_file_cache_min_uses 2;
# 开启错误信息缓存
open_file_cache_errors on;
了解了相关指令的参数后,我们通过一个实际案例来看看如何配置并验证 open_file_cache 的效果。
实践案例
步骤 01. 未开启缓存时的基准测试
首先,我们在 Nginx 配置中不启用 open_file_cache,以观察其默认行为。这里配置了两个 location 块,一个用于服务本地静态资源,另一个用于反向代理到上游 API 服务。
$ vim /usr/local/nginx/conf.d/test.conf
server {
listen 80;
server_name test.weiyigeek.top;
charset utf-8;
default_type text/html;
# 启用 HTTP/2 支持
http2 on;
# 日志文件
access_log /var/log/nginx/test.log main;
error_log /var/log/nginx/test.err.log debug;
# 静态资源 location 配置
location / {
root /usr/local/nginx/html/slice;
index index.html;
}
# 反向代理 location 配置
location ^~ /api/ {
proxy_pass http://10.20.172.213:8088/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
步骤 02. 分析未开启缓存时的系统调用
重启 Nginx 服务后,分别访问静态资源和反向代理接口,同时使用 strace 命令跟踪 Nginx 工作进程的系统调用。从下面的输出片段可以清晰地看到,在未开启缓存时,每次请求静态资源都会伴随着 openat(打开文件)和 close(关闭文件)的系统调用。对于高并发场景,这种频繁的 open/close 操作会成为明显的性能瓶颈。
# 查询 nginx worker 进程号
$ ps -ef | grep "nginx: worker process" | grep -v "grep"
nginx 653926 579435 0 08:18 ? 00:00:00 nginx: worker process
# 跟踪该进程,并请求静态资源 /index.html
$ strace -p 653926
strace: Process 653926 attached
...
recvfrom(4, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 596
openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 6 # 关键点: 系统调用 open 文件
...
sendfile(4, 6, [0] => [615], 615) = 615
close(6) = 0 # 关键点: 系统调用 close 文件
...
# 第二次请求同一个文件,依然会执行 open 和 close
recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 544
openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 20 # 关键点
...
close(20) = 0 # 关键点
提示:跟踪输出中的 sendfile 调用是一个积极的性能优化点,它利用了零拷贝技术,数据无需在内核态和用户态之间来回拷贝,直接从磁盘通过内核缓冲区发送到网卡,效率很高。
步骤 03. 启用 open_file_cache 优化
现在,我们修改 Nginx 配置文件,在静态资源服务的 location 块中启用 open_file_cache 及相关优化指令。
tee /usr/local/nginx/conf.d/test.conf <<'EOF'
server {
listen 80;
server_name test.weiyigeek.top;
charset utf-8;
default_type text/html;
# 启用 HTTP/2 支持
http2 on;
# 日志文件
access_log /var/log/nginx/test.log main;
error_log /var/log/nginx/test.err.log debug;
# 静态资源 location 配置
location / {
root /usr/local/nginx/html;
index index.html;
# 开启缓存,最大缓存1000个文件描述符,在60秒内未被访问将被移除
open_file_cache max=1000 inactive=60s;
# 每30秒检查缓存文件句柄的有效性,确保获取最新的文件信息
open_file_cache_valid 30s;
# 文件在60秒内最少被访问2次后才会被加入缓存
open_file_cache_min_uses 2;
# 开启错误信息缓存
open_file_cache_errors on;
}
# 反向代理 location 配置(此处不开启,因为代理不涉及本地文件句柄)
location ^~ /api/ {
proxy_pass http://10.20.172.213:8088/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
EOF
说明:本例仅在静态资源场景下配置了文件句柄缓存。反向代理通常不涉及打开本地文件,而是建立网络连接,因此无需在此处开启。
步骤 04. 验证优化效果
重新加载 Nginx 配置后,我们再次使用 strace 进行跟踪,并使用浏览器连续访问 http://test.weiyigeek.top/index.html 四次。
$ nginx -s reload
$ ps -ef | grep "nginx: worker process" | grep -v "grep"
nginx 670912 667054 0 11:24 ? 00:00:00 nginx: worker process
$ strace -p 670912
strace: Process 670912 attached
...
# 第一次请求:需要打开文件
recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 625
openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 17 # 关键点:首次打开
...
close(17) = 0 # 关闭
...
# 第二次请求:再次打开,根据`min_uses=2`的规则,此文件句柄将被加入缓存
recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 625
openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 17 # 关键点:第二次打开
...
# 注意:此次没有立即 close(17)!句柄被缓存。
...
# 第三次请求:直接使用缓存的文件句柄,无 open 调用!
recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 625
# 无 openat 系统调用!
writev(3, [{iov_base="HTTP/1.1 304 Not Modified\r\nServe"..., iov_len=180}], 1) = 180
...
# 第四次请求(F5刷新):依然直接使用缓存的文件句柄
recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "... 1024, 0, NULL, NULL) = 625
# 无 openat 系统调用!
sendfile(3, 17, [0] => [615], 615) = 615 # 直接使用已缓存的句柄 17 发送文件
...

从跟踪结果可以清晰看到优化效果:前两次访问执行了 open,从第三次开始,open 和 close 系统调用消失了,Nginx 直接使用了内存中缓存的文件句柄。这极大地减少了系统调用的开销,提升了请求处理效率。
总结
至此,我们完成了针对 Nginx 静态资源服务的两项核心性能优化实践:一是通过设置缓存控制头部(如 Expires, Cache-Control)来利用客户端缓存;二就是本文深入探讨的 open_file_cache,通过缓存文件句柄及相关元信息,从根本上减少了服务端的系统调用次数。
open_file_cache 是 Nginx 性能优化 中一个非常实用且强大的功能,在生产环境中应用广泛。合理配置它,可以显著提升静态资源服务的吞吐能力和响应速度,是每一位运维和开发人员都应该掌握的性能调优手段。更多深入的服务器优化技巧与配置实战,欢迎在 云栈社区 与广大开发者一同交流探讨。
