缓存不经常更新的动态信息:策略与 Nginx 配置指南
文章评论、排行榜、投票结果这类内容虽然是动态生成的,更新频率却不高,每次请求都打到后端太浪费。把它们缓存在 Nginx 代理层,后端压力和页面加载速度都会明显改善。这篇在 nginx:1.28 容器里把这套配置实跑一遍:命中、过期、后端宕机时的兜底,以及一个会让用户读到别人数据的缓存键错误。
哪些内容适合这样缓存
判据只有一条:动态生成、但更新频率以分钟或小时计。文章评论、排行榜、投票结果都在此列——每次请求实时计算是浪费;反过来,余额、订单状态这类时效敏感数据不适用,缓存换来的一致性代价不划算。
缓存策略
对这类内容推荐两层组合:较长的缓存时间 + 更新时主动清理。用户绝大多数请求命中缓存,内容更新后靠清理动作保证及时可见。缓存时间是”最差情况下用户读到多旧的数据”,清理机制才是实时性的来源,两者缺一不可。
Nginx 配置实例
缓存路径与键(http 块):
1 | proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:10m |
keys_zone=my_cache:10m 划出 10MB 共享内存存放缓存键和元数据;max_size=1g 限制缓存总大小;inactive=7d 表示 7 天没被访问就清除;use_temp_path=off 让缓存文件直接写入最终目录,省一次拷贝。
代理与缓存规则(server 块):
1 | location /dynamic-content/ { |
proxy_cache_valid 200 1h 把 200 响应缓存 1 小时;proxy_cache_use_stale 是后端故障时的兜底——后端报错、超时、5xx 时继续提供旧缓存;X-Cache-Status 头暴露每次请求的缓存状态,是调优时最重要的观测点。
实例一:MISS、HIT、EXPIRED 三种状态
容器实测(后端按 query 参数返回内容,TTL 设 3 秒便于观察;是否回源用后端 access.log 行数交叉验证),同一 URL 连续请求并观察响应头:

第一次 MISS(回源并写入缓存),第二次 HIT(直接命中缓存,内容的时间戳没变——后端没被碰);3 秒 TTL 过后再请求变成 EXPIRED(缓存过期,重新回源并刷新)。X-Cache-Status 的常用取值就是这四个:MISS、HIT、EXPIRED,加上接下来演示的 STALE。
实例二:后端宕机,use_stale 兜底
后端进程被 kill 后再请求同一 URL——缓存已过期、回源必失败,按常理应该是 502:

实测返回的是 STALE:Nginx 尝试回源失败(error 条件命中 proxy_cache_use_stale),把已过期的旧缓存继续返回给用户。这就是这条配置的价值:后端抖动、重启、发布期间,用户读到的最多是几秒前的旧数据,而不是错误页。对评论、排行榜这类内容,是完全可接受的降级。
错误写法对比:缓存键漏掉参数,用户读到别人的数据
缓存键决定”什么算同一个请求”。把键写成不含参数的形式($uri 而不是 $request_uri):
1 | # 错:缓存键没有 query string |
实测后果:

先请求 ?id=1(MISS,返回 id=1 的数据),再请求 ?id=2——返回的却是 id=1 的数据,且状态是 HIT。两个不同的请求被当成了同一个,用户 A 的数据串给了用户 B。这类错误在带登录态的接口上就是数据泄露事故;也是为什么要用 $request_uri(完整含参数)做键的基础。
注意事项
- 缓存时间与更新频率匹配:示例的 1 小时是”用户最多读到 1 小时前的数据”,能接受再设;配合”更新时主动清理”才能兼顾实时性。
- 主动清理不自带:需要 purge 模块或自研清理脚本(按缓存键删除文件/调接口),上线前先备好,否则内容更新后用户看不到。
- use_stale 是降级不是常态:它提供的是旧内容,对时效敏感的路径要慎用;配合
updating参数还能防止缓存过期瞬间的并发回源风暴。 - 上线后盯 X-Cache-Status:命中率长期偏低先查缓存键和 TTL,再查是否有 Set-Cookie 之类的响应头把响应变成了不可缓存。
小结
回到开头的场景:评论、排行榜这类低频更新内容,用 proxy_cache 三段配置(缓存区、缓存键、缓存规则)就能从后端卸掉大部分重复请求。实跑下来的要点:X-Cache-Status 是眼睛(MISS/HIT/EXPIRED/STALE 四态对应四种链路),use_stale 是后端故障时的安全网,而缓存键必须包含完整的请求参数——漏了就是数据串号事故。
本文由作者 2020-2024 年间的 CSDN 博客文章重构而来,原发布于 CSDN。