用 hash $request_uri consistent 可实现url级精确缓存命中,确保相同uri(含路径、参数、大小写、编码)始终路由至同一后端节点,提升本地或共享缓存复用率。

为什么必须用 $request_uri
$request_uri 是 Nginx 原生变量,值为原始请求行中的完整 URI(例如 /static/logo.png?v=2.5.0&ts=1718234567),具备三个关键特性:
- 包含完整路径与原始查询字符串,不丢弃参数 —— 区分
/api/user/123和/api/user/123?from=app,避免缓存误共享 - 区分大小写、不自动解码 ——
/IMG/LOGO.PNG和/img/logo.png视为不同请求,适合对资源版本敏感的场景 - 与资源本身强绑定,不受客户端网络环境影响 —— 避免
$remote_addr在 NAT/CDN 下失效或倾斜
基础 upstream 配置要点
以下配置必须严格满足,否则一致性哈希会失效或 Nginx 启动报错:
- 指令必须写作:
hash $request_uri consistent;——consistent参数不可省略,否则是普通取模哈希,节点增减时大量请求重映射 - 所有
server行不能带weight=、backup、max_fails等参数 —— 这些在原生 hash 模式下被忽略,且可能触发配置校验失败 - server 地址只写 IP+端口,例如:
server 10.0.2.10:8080;
应对真实请求干扰:URI 归一化处理
实际流量中,同一资源常因追踪参数(utm_*)、时间戳(_t=)、参数顺序不同导致哈希散列不一致。这时需预处理:
- 用
map指令剔除干扰参数,生成干净的哈希键:map $request_uri $clean_uri {<br> ~^(?<path>[^?]*)(?:\?(?<query>[^&]*&)*[^&]*)?$ $path;<br>}</query></path>
再对$clean_uri哈希(更稳妥做法是用 Lua 或 OpenResty 对查询参数排序并过滤) - 对静态资源路径做前缀提取,缓解热点倾斜:
map $request_uri $static_key {<br> ~^(/static/[^?]+)(?:\?.*)?$ $1;<br> default $request_uri;<br>}
然后hash $static_key consistent;
配合后端缓存策略才能真正生效
仅靠 Nginx 路由还不够,后端缓存行为必须对齐:
- 各后端服务生成的缓存 Key 规则要统一 —— 比如都忽略
utm_source、ref类参数,否则同一$request_uri在不同机器缓存的是不同内容 - 优先使用共享缓存(如 Redis 集群)而非纯内存缓存,避免单机容量瓶颈和冷启动问题
- Nginx 层开启
proxy_cache_lock on;,防止缓存未命中时多个相同请求并发穿透到后端
上线前快速验证是否生效
加一行响应头即可观测路由稳定性:
- 在
location块中添加:add_header X-Routed-To "$upstream_addr"; - 用
curl -I多次请求同一 URL(注意保持大小写和参数顺序),观察X-Routed-To值是否固定 - 对比开启前后缓存命中率变化 —— 典型静态资源集群可从 65% 提升至 90%+;后端各节点请求分布标准差应明显收窄











