大型项目缓存键设计核心是让每个key精准对应一个语义不可再分的响应结果;需按业务语义划分缓存域,用map预处理字段,显式声明关键维度,并通过响应头、日志和age头验证。

大型项目缓存键设计的核心不是“结构多复杂”,而是让每个 key 精准对应一个语义上不可再分的响应结果。Nginx 本身不管理层级或目录,它只对 proxy_cache_key 字符串做哈希存储;所谓“规范化”,本质是建立一套可复用、可验证、可演进的 key 构建逻辑。
按业务语义划分缓存域,隔离不同生命周期内容
避免所有请求共用一个 keys_zone 或一套 key 模板。应根据响应稳定性、更新频率、共享范围拆分缓存域:
- 静态资源(CSS/JS/图片):用
"$scheme$host$uri",彻底剔除$args,不区分参数 - 内容型页面(文章、商品详情):保留路径 + 白名单参数(如
$arg_lang、$arg_v),剔除utm_*、t=、random= - 用户级接口(如
/api/profile):必须纳入身份标识,但推荐哈希后使用,例如md5($cookie_user_id)或$http_x_user_id - 灰度/环境隔离接口:显式加入
$http_x_env或$arg_env,确保 prod 和 test 缓存不混用
用 map 预处理关键字段,保持 key 干净且可控
直接在 proxy_cache_key 行内拼接复杂逻辑易出错、难维护。应在 http 块中统一用 map 提前清洗和标准化:
- 清理 query 参数:
map $args $clean_args { ~^(.*&)?(utm_[^&]+&?)+(.*)?$ "$1$3"; default $args; } - 归一化语言标识:
map $http_accept_language $lang { ~zh "zh-CN"; ~en "en-US"; default "en-US"; } - 提取主题偏好:
map $http_cookie $theme { ~theme=(dark|light) $1; default "light"; } - 设备类型判断(比 UA 更稳):
map $http_x_requested_with $device { "XMLHttpRequest" "desktop"; "" "desktop"; default "mobile"; }
最终 key 组合示例:"$scheme$request_method$host$cache_uri|$lang|$theme|$device",用 | 分隔增强可读性与防冲突能力。
强制关键维度显式声明,杜绝隐式依赖
很多缓存污染问题源于 key 漏掉实际影响响应的变量。需逐接口确认后端是否读取以下字段,并只在必要时引入:
-
必须包含:请求方法(
$request_method),防止 HEAD 覆盖 GET 缓存 -
谨慎包含:
$cookie或$http_cookie—— 除非真依赖 session 或灰度 cookie,否则一律禁用;若需,只取特定字段并哈希 -
禁止包含:
$http_referer、$http_x_forwarded_for、$http_user_agent(高变、无业务意义) -
推荐替代:用自定义 header(如
$http_x_region、$http_x_user_role)代替不可控的原始头
上线前必做的三件事:验证、压测、监控
配置写完不等于生效。没有验证的 key 设计等于没做:
- 加响应头:
add_header X-Cache-Status $upstream_cache_status;,用curl -I对比带/不带 utm 的同一 URL,确认是否 HIT - 启用 cache 日志:
log_format cache '$cache_key - $upstream_cache_status';,抽样检查真实生成的 key 是否符合预期 - 观察
Age头变化,确认缓存是否真正复用而非每次都回源;临时设 key 为固定字符串(如"debug"),快速验证缓存模块是否加载成功











