✏️ 编辑

Nginx 缓存配置完全指南(实战总结)

创建于 2026-07-01 11:15:36 · 更新于 2026-07-05 09:19:35

Nginx 视频缓存配置完全指南

整理于 2026-07-01,基于个人运维平台视频服务的缓存配置实战排查全过程。


一、架构总览:一条请求的完整路径

你打开浏览器 → 请求到 Nginx → Nginx 问 Flask → Flask 渲染页面返回

三层缓存体系

① 浏览器缓存(Cache-Control)
    ↓ 没命中?
② Nginx proxy_cache(X-Cache: HIT/MISS)  ← 本文重点
    ↓ 没命中?
③ Flask 渲染页面(最慢)
资源类型 走哪条路 缓存谁控制 怎么看
HTML 页面(/videos、/note/1) → Nginx → Flask Nginx 的 proxy_cache_valid X-Cache: HIT
静态文件(.css、.js、图片) → Nginx 直接读磁盘 Nginx 的 expires + Cache-Control Cache-Control: max-age=...
B站播放器(iframe 嵌入) → 直接请求 B站服务器 B站的 CDN(你管不了) F12 → Network

二、核心概念

2.1 什么是 Nginx 缓存(proxy_cache)

Nginx 把后端(Flask)返回的页面存一份在磁盘上。下次同样的请求进来,Nginx 直接返回缓存,不再问 Flask。
1. proxy_pass 负责转给谁处理,没有它,Nginx 就自己读磁盘/返回静态文件(如 /static/)。有了它,才是"反向代理"。
2. proxy_cache 是 Nginx 做反向代理时,在代理层(Nginx 和后端应用之间)加的一层缓存。负责要不要缓存后端的结果。
proxy_cache micro_cache; #缓存到磁盘
proxy_cache_valid 200 60s; #缓存策略
命中 → 响应头出现 x-cache: HIT;未命中 → x-cache: MISS
3. proxy_ignore_headers — 后端响应头,但Nginx不听
4. add_header — 返回客户端前,额外加个头,只影响返回给客户端的响应,不影响 Nginx 内部的缓存逻辑。

动态资源(/videos/ /note/)流程:
1. 请求到达 Nginx
2. Nginx 通过proxy_pass反向代理指向proxy_cache代理缓存,根据 proxy_cache_key 生成缓存 key(key每次都不一样),先去磁盘缓存里查有没有
3. 有且未过期(x_cache:HIT) → 直接返回缓存,不再往后端转发
4. 没有或已过期(x_cache:MISS) → 转发给 Flask 后端,拿到响应后写入缓存,再返回给客户端

静态资源(static/css/js/图片)流程:
1.请求到达Nginx
2.Nginx直接读磁盘,缓存策略信息Cache-Control、Expires
3.返回给客户端,没有x_cache

2.2 缓存命中的三种状态

状态 翻译 意味着什么 你该怎么做
HIT 命中了 Nginx 直接返回缓存内容,没找 Flask。响应快,服务器省力 正常状态。如果用户说看不到新内容,调短 TTL
MISS 没命中 Nginx 缓存里没有,去问了 Flask。第一次访问或缓存已过期 偶尔 MISS 正常;总是 MISS 说明配置可能有问题
BYPASS 跳过了 这个请求 Nginx 故意不走缓存(如 POST、HEAD) 确认请求方式,非 GET 不用管

2.3 浏览器缓存 vs Nginx 缓存(疑惑点对比)

对比项 浏览器缓存 Nginx 缓存(proxy_cache)
存在哪里 用户本地浏览器 服务器磁盘(/var/cache/nginx/)
命中了会怎样 不发请求到服务器 发请求到 Nginx,但 Nginx 不找 Flask
怎么看 Cache-Control 响应头 X-Cache-Status 响应头
谁控制 expires 指令 proxy_cache_valid 指令

2.4 proxy_ignore_headers 与 add_header 的区别(疑惑点对比)

这两行配置容易混淆:

Nginx
proxy_ignore_headers Cache-Control Expires;   ← ① Nginx 自己内部用  # 忽略后端返回的缓存头
add_header X-Cache-Status $upstream_cache_status;  ← ② 返回给客户端的
配置 作用对象 给谁看的
proxy_ignore_headers Nginx 自己做缓存决策时用 内部用的,与外面无关
add_header X-Cache-Status 返回给客户端的响应 给你(curl/浏览器)看的

proxy_ignore_headers 的意思是: Flask 返回的 Cache-ControlExpires,Nginx 做缓存决策时当没听见。Nginx 只认自己的 proxy_cache_valid

X-Cache-Status 不是 Flask 给的,是 Nginx 自己加的变量。

2.5 Range 请求缓存

Range 请求是视频拖进度条时,播放器只请求某一小段数据(如 "bytes=0-1024")。

场景 结果
开启 Range 缓存 用户拖进度条 → Nginx 缓存里有 → 直接返回,秒拖
关闭 Range 缓存 用户拖进度条 → 每次都回源 → 卡顿、源站压力大

服务器返回 HTTP 206Content-Range 头表示这是一个范围响应。


三、实战命令大全

3.1 查看缓存状态(核心命令)

Bash
# 一条命令搞定:看响应头中的缓存状态
curl -sk https://zhoujiayi.xyz/videos -D - -o /dev/null 2>&1 | grep x-cache
-s:不显示进度条和错误信息;-k:跳过 SSL 证书验证
-D:表示只输出响应头(response headers);- 表示输出到屏幕
-o /dev/null:正文扔垃圾桶
2>&1:把错误信息塞进正确信息里
| grep x-cache:筛选出包含 x-cache 的行

# 输出示例
# x-cache-status: HIT
# x-cache-status: MISS
# x-cache-status: BYPASS

3.2 curl 参数详解

参数 作用
-s 安静模式,不显示进度条
-k 跳过 HTTPS 证书检查(自己的服务器不用纠结)
-I HEAD 请求,只要响应头不要正文
-D - 把响应头打印到屏幕上
-o /dev/null 正文扔垃圾桶,只看头
-o /dev/null -w "%{http_code}" 只看状态码
2>&1 错误信息也一起显示
| grep "关键词" 从结果中筛选关键词

3.3 参数组合对比(疑惑点对比)

命令 正文去哪了 头去哪了 适用场景
curl -sk https://... 打印到屏幕 也打印到屏幕(混在一起) 想看完整内容
curl -sk https://... -I 不要正文 打印到屏幕 只看头信息(但发的是 HEAD 请求,可能 BYPASS 缓存)
curl -sk https://... -o /dev/null 扔掉 也扔了 只看返回状态码(加 -w)
curl -sk https://... -D - -o /dev/null 扔掉 打印到屏幕 最常用的排查命令

注意: -I 发的是 HEAD 请求,如果 Nginx 配置了 if ($request_method != GET) 就会返回 BYPASS。所以排查缓存建议用 -D - 而不是 -I

3.4 Nginx 配置相关命令

Bash
# 查看当前视频缓存的 TTL
grep "proxy_cache_valid" /etc/nginx/conf.d/ops-platform.conf

# 修改 TTL(例如 300s → 600s)
sed -i 's/proxy_cache_valid 200 300s;/proxy_cache_valid 200 600s;/' /etc/nginx/conf.d/ops-platform.conf

# 检查 Nginx 配置语法
nginx -t

# 热重载 Nginx(不中断现有连接)
nginx -s reload

3.5 日志分析命令

Bash
# 查看最近几条请求日志
tail -5 /var/log/nginx/access.log

# 统计缓存命中次数
grep -c " HIT" /var/log/nginx/access.log
grep -c " MISS" /var/log/nginx/access.log
grep -c " BYPASS" /var/log/nginx/access.log

# 看实时请求(持续跟踪)
tail -f /var/log/nginx/access.log

# 查看 Nginx 错误日志(排查 403/500 等问题)
tail -20 /var/log/nginx/error.log

3.6 日志格式解读

一条典型的访问日志:

43.134.84.11 - - [01/Jul/2026:18:48:39 +0800] "GET /videos HTTP/2.0" 200 13787 HIT upstream=- total=0.000
字段 意思
43.134.84.11 访问者 IP 谁访问的
"GET /videos" 请求方法 + 路径 访问了哪个页面
200 状态码 正常返回
13787 字节数 页面大小
HIT 缓存状态 命中了缓存,没找 Flask
upstream=- Flask 耗时 - 表示根本没找 Flask,0ms
total=0.000 总耗时 0 秒,秒回

MISS 的日志对比:

... "GET /videos/16" 200 16315 MISS upstream=0.010 total=0.010
  • upstream=0.010 → Flask 花了 10ms 渲染
  • total=0.010 → 总共 10ms

3.7 静态文件排查

Bash
# 查看静态文件是否能正常加载
curl -skI https://zhoujiayi.xyz/static/css/style.css

# 检查文件路径权限链
namei -l /root/note-center/static/css/style.css

# 修复权限(Nginx 以 nginx 用户运行,需要能进入路径)
chmod o+rx /root

# 模拟 Range 请求(视频拖进度条)
curl -sk https://zhoujiayi.xyz/static/css/style.css -H "Range: bytes=0-1024" -D - -o /dev/null 2>&1 | grep -i "http/\|content-range"

四、Nginx 缓存配置结构

4.1 视频服务专属缓存规则

Nginx
# 视频列表页:5 分钟缓存
location /videos {
    proxy_cache micro_cache;  # 使用上面定义的缓存区
    proxy_cache_key "$scheme$host$request_uri";
    proxy_cache_valid 200 300s; # 200 状态的响应缓存 300 秒
    proxy_cache_valid 404 5s;
    proxy_cache_use_stale error timeout updating;
    proxy_cache_lock on;
    proxy_ignore_headers Cache-Control Expires;
    proxy_pass http://flask_backend;
    add_header X-Cache-Status $upstream_cache_status;
}

# 缓存配置与排错指南(内容稳定,10 分钟缓存)
location ~ ^/(video-cache|video-troubleshooting) {
    proxy_cache micro_cache;
    proxy_cache_valid 200 600s;
    ...
}

4.2 各页面缓存策略对比

页面 缓存时长 理由
视频列表 /videos 5 分钟 不会频繁增删,5 分钟足够
播放页 /videos/16 5 分钟 播放次数 5 分钟后自动更新
缓存配置 /video-cache 10 分钟 几乎不动的内容
排错指南 /video-troubleshooting 10 分钟 纯文档,几乎不改
黄金价格 /gold 1 小时 每天只更新一次
笔记查看 /note/\d+ 5 分钟 笔记内容相对稳定
监控面板 /monitor 不缓存 需要保持实时
静态文件 /static/ 30 天(浏览器缓存) 文件不变,长久缓存

4.3 生产环境最佳实践

Nginx
proxy_cache_path /var/cache/nginx/micro levels=1:2 keys_zone=micro_cache:5m max_size=256m inactive=5m;

参数含义:
- keys_zone=micro_cache:5m:缓存索引在内存中占 5MB
- max_size=256m:缓存文件最大占 256MB 磁盘
- inactive=5m:5 分钟没被访问的缓存自动清除


五、完整排查流程

5.1 用户说"慢"

1. curl -sk https://域名/页面 -D - -o /dev/null 2>&1 | grep x-cache
   → HIT:慢的不是 Nginx,可能是 B站播放器加载慢(外部原因)
   → MISS:缓存没命中,去查 Flask 了

2. 如果一直 MISS,检查 TTL:
   grep "proxy_cache_valid" /etc/nginx/conf.d/ops-platform.conf

3. 如果 TTL 太短,调整:
   sed -i 's/旧值/新值/' 配置文件名
   nginx -t && nginx -s reload

5.2 用户说"看不到新内容"

1. 先 curl 查缓存状态
   → HIT:说明 Nginx 返回了旧缓存 → TTL 太长 → 调短

2. 或者手动预热/刷新缓存
   curl -sk https://域名/页面 -o /dev/null  # 预热
   # CDN 厂商控制台执行 URL 刷新(如果有 CDN)

5.3 页面样式丢了

1. 检查静态文件能否加载
   curl -skI https://域名/static/css/style.css

2. 如果返回 403,看 Nginx 错误日志
   tail -20 /var/log/nginx/error.log
   → Permission denied → 检查文件路径权限

3. 修复权限
   namei -l /root/note-center/static/css/style.css  # 看哪一级目录权限不足
   chmod o+rx /目录名  # 给 nginx 用户加进入权限

六、核心原则

6.1 关于缓存命中率

  • HIT 是常态,MISS 是过程,连续 MISS 才是问题
  • 缓存命中率 = HIT 次数 ÷(HIT + MISS)次数 × 100%
  • 命中率 > 70% 为良好
    情况一:MISS 是你想解决的"问题"
    比如首页 / 配了 60s 缓存,但每次请求都是 MISS,说明缓存根本没用上。排查方向:
  • 先看是什么导致 key 不同
    tail -100 /var/log/nginx/access.log | grep MISS
    如果 URL 参数每次都不一样 → 是请求方的问题,不是服务器的问题(你之前遇到的情况)
  • 检查是不是后端返回了干扰头
    curl -skI https://zhoujiayi.xyz/ | grep -iE 'cache-control|expires|set-cookie|no-cache'
    如果 Flask 返回了 Cache-Control: no-cache 或 Set-Cookie,Nginx 默认不会缓存。
    ✅ 解决:你已经配了 proxy_ignore_headers Cache-Control Expires Set-Cookie;,这个没问题了。
  • 检查缓存空间是不是满了
    df -h /var/cache/nginx/micro # 看分区有没有满
    du -sh /var/cache/nginx/micro # 当前缓存占了多少
    你的配置 max_size=256m,如果满了会淘汰旧条目,但不会导致全 MISS。
  • 缓存文件权限
    namei /var/cache/nginx/micro
    确保 Nginx worker 进程有读写权限。
    情况二:MISS 本身不是问题,看命中率。但只能看总数
    grep -c " HIT" /var/log/nginx/access.log # → 3
    grep -c " MISS" /var/log/nginx/access.log # → 24

6.2 关于 TTL 设置

  • 内容越稳定,TTL 越长
  • 热门视频可短些,冷门可长些
  • 浏览器缓存 < CDN 节点缓存 < 源站缓存
  • 视频服务建议:浏览器 1h,CDN 1d,源站 7d

6.3 关于生产环境

  • 开发环境(Flask 自带服务器):无缓存,适合调试
  • 生产环境(Nginx + Flask):加缓存,加日志,加监控
  • 你的架构中 CDN 边缘节点 = Nginx 服务器本身(只有 1 台,不是真正的多节点 CDN)

七、日常自查清单

Bash
# ① 看缓存是否命中
curl -sk https://zhoujiayi.xyz/videos -D - -o /dev/null 2>&1 | grep x-cache

# ② 看当前 TTL 配置
grep "proxy_cache_valid" /etc/nginx/conf.d/ops-platform.conf

# ③ 看日志中的 HIT/MISS 统计
grep -c " HIT" /var/log/nginx/access.log
grep -c " MISS" /var/log/nginx/access.log

# ④ 看最近请求
tail -5 /var/log/nginx/access.log

八、实例演练:保存笔记后仍显示旧内容

Bash
### 1、问题现象

   在 Note Center 编辑笔记 → 点保存 → 页面重定向回笔记页 → 显示的还是旧内容。
   `Ctrl+F5` 无效,curl 查却能拿到新内容。

###2、排查步骤
第一步:确认是不是你自己电脑的问题
  按 Ctrl + F5(或 Cmd + Shift + R)硬刷新一次。
  - 如果变新内容了 → 就是浏览器缓存了旧页面
  - 如果还是旧的 → 往下走
第二步:确认 Nginx 是否缓存了旧页面
  在命令行跑一次,不走浏览器:
  curl -sk https://zhoujiayi.xyz -D - -o /dev/null 2>&1 | grep -i x-cache
  看输出是 HIT 还是 MISS 还是没内容。
  - 没有 x-cache(或 -) → 说明没走缓存层,往下走
  - HIT → 说明 Nginx 返回了它缓存里的旧页面
  - MISS / EXPIRED → 说明 Nginx 没有缓存或已过期,往下走
第三步:确认页面内容到底更新了没有
  curl -sk https://zhoujiayi.xyz | grep '你改的文字(取一小段)'
  - 如果搜到新文字 → 后端已经更新了,问题在前端(浏览器缓存或 CDN)
  - 如果还是旧文字 → 后端确实没更新,问题出在保存环节
第四步:找到问题所在
curl 搜到新文字,浏览器是旧的——浏览器缓存——Ctrl+F5 就行
curl 搜到新文字,但 x-cache 显示 HIT——Nginx 缓存没过期——清 Nginx 缓存
curl 也是旧文字——根本没保存成功——检查保存逻辑或数据库

### 3、请求链路还原
grep '/note/38' /var/log/nginx/access.log | tail -10

   ```
  01:19:55  ← 你看笔记 → /note/38 → HIT(Nginx 缓存了旧版本,有效期 10 分钟)
  01:20:04  ← 进编辑页 → /note/38/edit
  01:22:19  ← 点保存 → 302 跳到 /note/38?saved=1 → MISS(拿到了新内容)
             但此刻 /note/38(不带 ?saved=1)的旧缓存还在!
  01:21:39  ← 刷新 /note/38(没参数)→ 全 HIT → 旧内容
  01:25:24  ← 10 分钟后缓存过期了 → EXPIRED → 拿到新内容
   ```

### 4、根因分析
浏览器发请求到 Nginx → Nginx 看自己的缓存还有效(HIT)→ 直接返回旧的 → 浏览器收到旧内容。Ctrl+F5 只清你浏览器的缓存,Nginx 服务器上的 proxy_cache 它管不着。
第二次保存的时间点,10 分钟缓存已经过期了(01:25:24 已经开始 EXPIRED 了),所以浏览器拿到的是新数据。
   1. 第一次保存,Flask 写数据库,返回 302 重定向到 `/note/38?saved=1` (?saved=1改变页面内容/行为)
   2. /note/38 之前已经缓存了 10 分钟
   3. `?saved=1` 改变了缓存 key,所以 `/note/38?saved=1` 能拿到新内容
   4. 但 `/note/38`(不带参数)的旧缓存条目还活着(TTL 10 分钟)
   5. 任何对 `/note/38` 的请求依然命中旧缓存
   6. `Ctrl+F5` 只清浏览器缓存,管不到 Nginx 的服务端缓存

### 解法

● 方案一(推荐)**:在笔记 location 也加上 saved=1 的 bypass:

   ```nginx
   location ~ ^/note/\d+$ {
       proxy_cache micro_cache;
       proxy_cache_valid 200 600s;
       proxy_cache_valid 404 5s;
       proxy_cache_use_stale error timeout updating;
       proxy_cache_lock on;
       proxy_ignore_headers Cache-Control Expires;

       # 保存/删除/恢复后跳过并清缓存
       set $cache_bypass "";
     nginx: configuration file /etc/nginx/nginx.conf test is successful

  Thought for 1s (ctrl+o to expand)

● 方案二:
该proxy_cache_valid
  - /note/ 缓存时间:~~600s~~ → 200s
  - 配置检查通过,已重新加载

  保存笔记后最多等 200 秒(3 分 20 秒),缓存就会过期,刷新就能看到新内容了。

写在最后

Nginx 缓存排查的核心就是三句话:

  1. curl -D - -o /dev/null | grep x-cache — 实时看缓存状态
  2. grep proxy_cache_valid — 看当前 TTL 配了多少
  3. nginx -t && nginx -s reload — 改完配置后加载生效