直接看$upstream_cache_status分布即可判断cdn回源是否“瞎忙”:hit表示命中缓存不回源,miss/expired/bypass/stale等均触发回源,需结合日志配置、状态归因与缓存策略优化精准压降无效回源。

直接看 $upstream_cache_status 的分布,就能判断 CDN 回源是否“瞎忙”。它不是统计“有没有缓存”,而是告诉你每次请求到底经历了什么——是直取缓存(HIT),还是被迫回源(MISS/EXPIRED),甚至带病上岗(STALE)。回源成本高,本质是无效请求多、缓存没用好。
一、从日志里捞出真实缓存行为
默认 access_log 不记录这个变量,必须显式配置:
- 在
http或server块中定义日志格式,包含$upstream_cache_status:log_format cache_stat '$remote_addr [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $upstream_cache_status $upstream_response_time $request_time'; - 在静态资源或 CDN 回源 location 中启用:
access_log /var/log/nginx/cdn_hit.log cache_stat; - 加响应头辅助调试:
add_header X-Cache-Status $upstream_cache_status;
这样每条日志末尾都会带状态码(如 HIT、EXPIRED、BYPASS),可直接用 awk、goaccess 或 ELK 聚合分析。
二、按状态归因,精准定位回源原因
不同状态对应不同优化方向,不能只盯着 HIT 率数字:
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
- HIT:理想状态,缓存命中并返回,不回源
-
MISS:缓存未建立,首次访问或 key 不匹配;检查
proxy_cache_key是否含无关参数(如utm_*、sessionid)导致缓存碎片 -
EXPIRED:缓存存在但过期,强制回源;说明
proxy_cache_valid设置偏短,或后端响应头Cache-Control覆盖了 Nginx 配置 - STALE:后端不可用时用了过期缓存;暴露的是上游稳定性问题,不是缓存策略问题
-
BYPASS:请求被
proxy_cache_bypass显式跳过;常见于带 Cookie 或特定 header 的请求,需确认是否误判为“动态” -
UPDATING:缓存过期但正在后台更新,前端拿到旧内容;说明启用了
proxy_cache_use_stale updating,属正常容错,但高频出现可能意味着回源压力大
三、针对性压降回源频次
根据日志统计结果,调整三项核心配置:
-
延长有效缓存时间:对
200、304响应,把proxy_cache_valid提到合理值(如静态资源设为1h或24h),同时确保后端不返回Cache-Control: no-cache -
收紧缓存键范围:避免
$args引入干扰项,改用proxy_cache_key "$host$uri";或正则过滤参数(如用map剔除__t=类时间戳) -
拦截无效绕行请求:检查
proxy_cache_bypass和proxy_no_cache条件,防止因$cookie_xxx或$arg_debug导致整类请求被排除
四、联动 CDN 层做协同优化
Nginx 日志里的状态,还能反推 CDN 配置是否合理:
- 若大量
MISS出现在同一路径但不同User-Agent或Accept-Encoding,说明 CDN 缓存键分裂严重,应在 CDN 控制台关闭Vary头识别,或统一后端输出 gzip - 若
EXPIRED比例高,而 CDN TTL 设置远大于 Nginx 的proxy_cache_valid,说明 CDN 在“空转”——它缓存了,但源站不让它信,应拉齐两端 TTL - 对比
$upstream_response_time和$request_time:若差值小但EXPIRED多,说明是缓存策略问题;若差值大,说明回源本身慢,需优化后端或增加连接复用(keepalive)
不复杂但容易忽略。关键不是堆指标,而是让每个状态都说话。










