信阳市网站建设_网站建设公司_域名注册_seo优化
2026/1/11 12:43:15 网站建设 项目流程

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ]

📢 大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 🚀,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路 😋 。

Nginx 使用 open_file_cache 缓存文件句柄及其信息提升性能

前面文章中我们一起学习了 Nginx 前端、后端(反向代理)缓存机制,并且实践了如何配置 Nginx 在不同环境下缓存,在此基础之上,本章将讲解 Nginx 中另外一个非常重要的缓存功能open_file_cache,它通过缓存文件句柄及其信息,如修改时间、大小等,显著提升性能,尤其是避免频繁的open和close操作减少系统调用开销,对于优化 NGX 性能非常有帮助。

OK,接下来我们来看看 open_file_cache 缓存什么,它又是怎样对性能提示起到帮助的,最后通过一个案例来讲解如何配置 Nginx 的open_file_cache缓存功能。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_19oatlbj0w64.html

简单介绍

open_file_cache 属于 ngx_http_core_module 模块中的指令,其默认已经编译安装进入 Nginx,但是默认是不开启的,它可以缓存以下元信息:

  • [x] 文件句柄(fb): 缓存它意味着打开文件后不用每次 close 文件,并且再次使用时不用 open 文件,直接使用文件句柄即可,从而减少系统调用,提高性能

  • [x] 文件修改时间(mtime): 缓存它意味着在文件被频繁访问时,无需每次都调用 stat 系统调用来获取文件的修改时间

  • [x] 文件大小(size): 缓存它意味着在文件被频繁访问时,无需每次都调用 stat 系统调用来获取文件的大小

  • [x] 错误信息(err): 做文件查询中文件无权限访问时响应 403 Forbidden,无需每次都调用 stat 系统调用来获取文件的错误信息

  • [x] 文件存在性与类型: 缓存它意味着在文件被频繁访问时,无需每次都调用 stat 系统调用来判断文件是否真实存在

weiyigeek.top-open_file_cache缓存的元信息图

此外,open_file_cache 不仅适用于静态资源,还广泛用于日志和缓存文件操作,值得注意的时为保持缓存一致性,需合理设置超时时间,适应文件可能被外部进程频繁修改的场景。


指令参数

open_file_cache指令在内存缓存打开文件的描述符,减少文件打开操作的次数,设定max值限制缓存文件数量,利用链表淘汰机制和inactive时间参数管理缓存,确保资源有效利用

Syntax: open_file_cache off; open_file_cache max=N [inactive=time]; Default: open_file_cache off; Context: http, server, location # 参数说明: max=N 设置内存缓存的最多元素数量,默认为1024个文件描述符,当缓存元素数量超过这个值时,会按照inactive参数指定的时间间隔进行清理最少使用(LRU)的元素。 inactive 设置缓存元素的有效时间,默认为60s,如果元素在此时间内未被访问,则该元素将从该缓存中清除。 off 关闭缓存功能,等同于不配置该指令

open_file_cache_error指令用于启用或禁用文件查找错误的缓存, 在缓存有效期内会直接返回之前的错误信息而不会重新进行打开操作,减少不必要的系统调用。

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指令用于检查缓存文件句柄的有效性,确保文件被外部进程更新后,能够取得最新的文件信息,避免取得过时的文件内容。

Syntax: open_file_cache_valid time; Default: open_file_cache_valid 60s; Context: http, server, location

下面是 Nginx 官网文档给出的一个配置示例,用于演示如何使用open_file_cache相关指令。

Example: # 开启缓存,最大缓存1000个文件描述符,在单位时间 60s 内未被访问将被移除 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相关指令的参数,接下来通过一个实际例子来讲解如何配置 Nginx 的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命令查看系统调用情况,由下图可以看出,在未开启open_file_cache缓存功能时,访问静态资源会频繁的进行 open 和 close 系统调用,对于性能明显有影响。

# 查询到 nginx work 进程号,这里为 653926 $ ps -ef | grep "nginx: worker process" | grep -v "grep" nginx 653926 579435 0 08:18 ? 00:00:00 nginx: worker process # 请求本地静态资源时,查看 nginx 工作进程的系统调用情况,可以发现 open 和 close 系统调用 $ strace -p 653926 strace: Process 653926 attached epoll_wait(19, [], 512, 1223) = 0 # 等待外部请求进来 epoll_wait(19, [{events=EPOLLIN, data={u32=864584440, u64=139707560788728}}], 512, 5000) = 1 # 外部请求进来 accept4(13, {sa_family=AF_INET, sin_port=htons(57858), sin_addr=inet_addr("10.20.10.103")}, [112 => 16], SOCK_NONBLOCK) = 4 # 接收外部请求 epoll_ctl(19, EPOLL_CTL_ADD, 4, {events=EPOLLIN|EPOLLRDHUP|EPOLLET, data={u32=864584936, u64=139707560789224}}) = 0 # 将外部请求加入 epoll 事件监听 epoll_wait(19, [{events=EPOLLIN, data={u32=864584936, u64=139707560789224}}], 512, 16) = 1 # 外部请求到来,开始处理 recvfrom(4, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 596 # 读取外部请求内容 getrandom("\xd1\x92\x36\x92", 4, 0) = 4 getrandom("\xfe\xa1\x0a\x52", 4, 0) = 4 getrandom("\xd3\x6a\xdb\xb4", 4, 0) = 4 getrandom("\x1c\x85\x2b\x2f", 4, 0) = 4 openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 6 # 关键点: 系统调用 open 打开文件 newfstatat(6, "", {st_mode=S_IFREG|0644, st_size=615, ...}, AT_EMPTY_PATH) = 0 writev(4, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=253}], 1) = 253 sendfile(4, 6, [0] => [615], 615) = 615 # 关键点:sendfile 是一个优化点,利用零拷贝技术,减少内核态与用户态的切换。 write(15, "10.20.10.103 - - [09/Jan/2026:0"..., 236) = 236 getsockname(4, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("10.20.172.214")}, [112 => 16]) = 0 close(6) = 0 # 关键点:系统调用 close 关闭文件 epoll_wait(15, [{events=EPOLLIN, data={u32=304555240, u64=140402785461480}}], 512, 3930) = 1 recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 544 # 再次请求相同的外部资源时,仍然会进行 open 和 close 系统调用 openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 20 # 关键点 newfstatat(20, "", {st_mode=S_IFREG|0644, st_size=615, ...}, AT_EMPTY_PATH) = 0 writev(3, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=253}], 1) = 253 sendfile(3, 20, [0] => [615], 615) = 615 write(8, "10.20.10.103 - - [09/Jan/2026:1"..., 236) = 236 close(20) = 0 # 关键点 epoll_wait(15, [], 512, 1721) = 0 write(18, "\1\0\0\0\0\0\0\0", 8) = 8 epoll_wait(15, strace: Process 653926 detached <detached ...> # 请求反向代理上游资源时,查看 nginx 工作进程的系统调用情况 $ strace -p 653926 strace: Process 653926 attached epoll_wait(19, [], 512, 1813) = 0 epoll_wait(19, [{events=EPOLLIN, data={u32=864584936, u64=139707560789224}}], 512, 5000) = 1 # 外部请求进来 recvfrom(4, "GET /api/getuser HTTP/1.1\r\nHost:"..., 1024, 0, NULL, NULL) = 545 # 读取外部请求内容 epoll_ctl(19, EPOLL_CTL_MOD, 4, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=864584936, u64=139707560789224}}) = 0 # 将外部请求加入 epoll 事件监听 socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 6 ioctl(6, FIONBIO, [1]) = 0 epoll_ctl(19, EPOLL_CTL_ADD, 6, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=864585184, u64=139707560789472}}) = 0 connect(6, {sa_family=AF_INET, sin_port=htons(8088), sin_addr=inet_addr("10.20.172.213")}, 16) = -1 EINPROGRESS (Operation now in progress) # 连接反向代理上游服务器 epoll_wait(19, [{events=EPOLLOUT, data={u32=864584936, u64=139707560789224}}], 512, 4456) = 1 epoll_wait(19, [{events=EPOLLOUT, data={u32=864585184, u64=139707560789472}}], 512, 4455) = 1 getsockopt(6, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 # 连接成功 writev(6, [{iov_base="GET /getuser HTTP/1.0\r\nHost: tes"..., iov_len=739}], 1) = 739 # 发送请求到反向代理上游服务器 epoll_wait(19, [{events=EPOLLIN|EPOLLOUT, data={u32=864585184, u64=139707560789472}}], 512, 4455) = 1 # 等待反向代理上游服务器响应,开始处理 recvfrom(6, "HTTP/1.1 200 OK\r\nX-Powered-By: E"..., 4096, 0, NULL, NULL) = 1380 # 接收反向代理上游服务器响应 close(6) = 0 # 关闭反向代理上游服务器连接 writev(4, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=237}, {iov_base="{\n \"path\": \"/getuser\",\n \"heade"..., iov_len=1170}], 2) = 1407 # 将反向代理上游服务器响应发送给外部请求者 write(15, "10.20.10.103 - - [09/Jan/2026:0"..., 238) = 238 epoll_wait(19, strace: Process 653926 detached <detached ...>

温馨提示:上述事件中有一个 sendfile 它是一个优化点,利用零拷贝技术,减少内核态与用户态的切换,即磁盘中文件不需要先读到用户态,再从用户态发送到内核态,而是直接从内核态只能够将磁盘内容发送到网卡,所以说其性能很高。

温馨提示:Nginx 在等待外部请求进来时处于 epoll_wait 阶段,这个我们在前面文章《Nginx | 核心知识150讲,百万并发下性能优化之事件驱动框架笔记》中已经讲解过,当外部请求进来时,Nginx 会从 epoll_wait 阶段切换到系统调用阶段。


步骤 03.更改 Nginx 配置文件,启用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个文件描述符,在单位时间 60s 内未被访问将被移除 open_file_cache max=1000 inactive=60s; # 30秒内检查缓存文件句柄的有效性,确保获取最新的文件信息 open_file_cache_valid 30s; # 单位时间内最少使用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 # 查看 nginx 工作进程的 PID $ ps -ef | grep "nginx: worker process" | grep -v "grep" nginx 670912 667054 0 11:24 ? 00:00:00 nginx: worker process # 查看 nginx 工作进程的系统调用情况 $ strace -p 670912 strace: Process 670912 attached epoll_wait(15, [{events=EPOLLIN, data={u32=3197899512, u64=139623994757880}}], 512, -1) = 1 accept4(13, {sa_family=AF_INET, sin_port=htons(65250), sin_addr=inet_addr("10.20.172.103")}, [112 => 16], SOCK_NONBLOCK) = 3 epoll_ctl(15, EPOLL_CTL_ADD, 3, {events=EPOLLIN|EPOLLRDHUP|EPOLLET, data={u32=3197900008, u64=139623994758376}}) = 0 epoll_wait(15, [{events=EPOLLIN, data={u32=3197900008, u64=139623994758376}}], 512, 60000) = 1 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 # 关键点 recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 587 writev(3, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=253}], 1) = 253 sendfile(3, 17, [0] => [615], 615) = 615 write(8, "10.20.172.103 - - [09/Jan/2026:1"..., 234) = 234 close(17) = 0 # 关键点, setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 epoll_wait(15, [{events=EPOLLIN, data={u32=3197900008, u64=139623994758376}}], 512, 65000) = 1 recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 625 # 第二打开文件句柄,加入缓存(由于前面设置了 open_file_cache_min_uses 指令最少两次),后续2️⃣次访问均命中缓存 openat(AT_FDCWD, "/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 17 # 关键点,在内存中缓存了文件句柄,并且在缓存时间内不关闭文件句柄,后续也不再打开文件句柄。 newfstatat(17, "", {st_mode=S_IFREG|0644, st_size=615, ...}, AT_EMPTY_PATH) = 0 writev(3, [{iov_base="HTTP/1.1 304 Not Modified\r\nServe"..., iov_len=180}], 1) = 180 write(8, "10.20.172.103 - - [09/Jan/2026:1"..., 234) = 234 epoll_wait(15, [{events=EPOLLIN, data={u32=3197900008, u64=139623994758376}}], 512, 65000) = 1 # 第三次访问,直接返回304状态码,不再打开文件句柄,而是直接使用缓存文件句柄 recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 625 writev(3, [{iov_base="HTTP/1.1 304 Not Modified\r\nServe"..., iov_len=180}], 1) = 180 write(8, "10.20.172.103 - - [09/Jan/2026:1"..., 234) = 234 epoll_wait(15, [{events=EPOLLIN, data={u32=3197900008, u64=139623994758376}}], 512, 65000) = 1 # 最后一次,使用 F5 刷新访问,不再打开文件句柄,而是直接使用缓存文件句柄 recvfrom(3, "GET /index.html HTTP/1.1\r\nHost: "..., 1024, 0, NULL, NULL) = 625 writev(3, [{iov_base="HTTP/1.1 200 OK\r\nServer: nginx/1"..., iov_len=253}], 1) = 253 sendfile(3, 17, [0] => [615], 615) = 615 write(8, "10.20.172.103 - - [09/Jan/2026:1"..., 236) = 236 epoll_wait(15,

weiyigeek.top-缓存文件句柄及其信息效果图

至此,我们已经完成了 Nginx 静态资源服务性能优化的两大核心步骤,一则是返回给客户端的缓存头,另外一个就是 open_file_cache 利用其缓存文件句柄和其它信息,减少系统调用从而提升性能。

好了,以上我们介绍了 Nginx 中 Open_File_Cache 缓存文件句柄及其信息功能,此功能使用范围非常广泛,也是生产环境中常用的一个功能,它可以大幅度提升静态资源服务的性能。

END

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,持续更新包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。

Q: 加入作者【全栈工程师修炼指南】星球后有啥好处?

✅ 将获得作者最新工作学习实践文章以及网盘资源。

✅ 将获得作者珍藏多年的全栈学习笔记(需连续两年及以上老星球友,也可单次购买)

✅ 将获得作者专门答疑学习交流群,解决在工作学习中的问题。

✅ 将获得作者远程支持(在作者能力范围内且合规)。

获取:作者工作学习全栈笔记

作者整理了10年的工作学习笔记(涉及网络、安全、运维、开发),需要学习实践笔记的看友,可添加作者微信或者回复【工作学习实践笔记】,当前价格¥299,除了获得从业笔记的同时还可进行问题答疑以及每月远程技术支持,希望大家多多支持,收获定大于付出!

知识推荐往期文章

  • 🔥【最新】5大互联网慈善机构,各种白嫖,你用过几个

  • 🔥【最新】Nginx | slice 模块,实现上游大文件“化整为零”缓存

  • 🔥【最新】中国移动所有省份套餐,都在这官方公示页面

  • 💡【相关】Nginx | 核心知识150讲,百万并发下性能优化之其它HTTP框架下反向代理场景

  • 💡【相关】Nginx | 核心知识150讲,百万并发下性能优化之前端静态缓存、后端动态缓存实践笔记

  • 💡【相关】Nginx | 核心知识150讲,百万并发下性能优化之SSL证书签发与HTTPS加密传输实践笔记

若文章对你有帮助,请将它转发给更多的看友,若有疑问的小伙伴,可在评论区留言你想法哟 💬!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询