page cache 占满内存并非故障而是内核设计行为,真正风险在于 available 持续低于5%~8%引发回收抖动与swap;应通过调优 vm.vfs_cache_pressure=200、vm.swappiness=1、dirty_ratio/ background_ratio 及 sendfile+noatime 等方式平滑管理缓存。

这不是内存被“侵占”,而是 Linux 内核按设计把磁盘缓存(Page Cache)填满了——proxy_cache 读取文件时,Nginx 加载的每个响应体都会经由内核路径落进 Page Cache,只要内存空闲,就会一直缓存。真正的问题是:缓存没被有效管理,导致可用内存(available)持续逼近水位线,触发频繁回收、IO抖动、甚至 swap,最终表现为响应延迟波动大、P95/P99 毛刺明显。
确认是否真是 Page Cache 压力所致
别只看 free -h 的 used 高就动手清缓存。重点查三件事:
- available 是否持续低于总内存的 5%~8%(例如 64G 机器长期
- vmstat 1 看 si/so 是否非零且波动上升(有 swap 进出 = 内存已紧张)
- cat /proc/meminfo | grep -E "Cached|Buffers|SReclaimable|MemAvailable" —— 若 Cached 占比超 60%,而 SReclaimable 高(说明大量可回收页),但 MemAvailable 持续低位,就是 Page Cache 挤占了调度弹性空间
限制 proxy_cache 的实际缓存粒度与生命周期
Nginx 的 proxy_cache 默认会把整个响应体塞进文件系统,再由内核缓存到内存。这不是高效做法,尤其对大静态资源(如视频切片、大 JS/CSS)。应主动收缩缓存面:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 用
proxy_cache_valid 200 302 1m;缩短默认缓存时间,避免长期驻留冷数据 - 加
proxy_cache_min_uses 3;,只缓存被重复请求 ≥3 次的资源,过滤一次性流量 - 对大文件(>1MB)显式绕过 cache:
proxy_no_cache $request_uri ~* \.(mp4|avi|zip|tar\.gz)$; - 启用
proxy_cache_use_stale updating;减少回源并发,间接降低 cache 写入频次
调优内核 Page Cache 回收行为
不靠 drop_caches 这种暴力手段(它会造成瞬时 IO 尖峰,反而加剧颠簸),而是让内核更早、更平滑地释放冷页:
- 提高 vfs cache 压力:设
vm.vfs_cache_pressure=200(默认 100),加快 dentry/inode 回收,减少路径查找开销和元数据驻留 - 收紧脏页刷盘节奏:若后端写压力大,调低
vm.dirty_ratio=15和vm.dirty_background_ratio=5,避免脏页堆积挤占干净 pagecache 空间 - 降低 swap 倾向:设
vm.swappiness=1,强制内核优先回收 pagecache 而非换出匿名页,防止响应进程被 swap 影响
绕过 Page Cache 的直通路径(适用于只读大资源)
对确定不会修改、且体积较大(如 CDN 分发的媒体文件),可让 Nginx 绕过内核缓存,直接 sendfile + O_DIRECT 或使用 sendfile_max_chunk 分块推送:
- 确保
sendfile on;开启,并配tcp_nopush on; - 加
sendfile_max_chunk 512k;防止单次 sendfile 锁住大内存页 - 若文件系统支持且内核 ≥5.10,可考虑挂载时加
noatime,relatime减少元数据更新,间接降低 cache 压力










