hash $request_uri可实现基于完整URI(含查询参数)的一致性哈希分发,确保相同URL固定路由至同一后端,适用于缓存亲和、灰度测试等场景;需注意其区分大小写、不自动解码、参数顺序敏感等特性,推荐加consistent提升伸缩稳定性。

利用 hash $request_uri 可以在 Nginx 中实现基于完整请求 URI(含查询参数)的一致性哈希分发,适合需要将相同 URL 长期固定到同一后端的场景,比如缓存亲和、灰度测试或避免重复计算。
理解 hash $request_uri 的行为特点
$request_uri 是 Nginx 内置变量,值为原始请求行中的 URI(例如 /api/user?id=123&v=2),包含路径和完整查询字符串,且不进行解码或标准化。使用 hash 指令对其做哈希时:
- 相同 URI 字符串每次计算出的哈希值一致,保证同一 URL 总落到同一 upstream server
- URI 中任意字符差异(如大小写、空格、编码形式、参数顺序)都会导致哈希结果不同
- 后端节点增减时,部分 URI 映射会变动(标准哈希特性,非一致性哈希);如需更稳定的映射,应改用
hash $request_uri consistent;
配置示例:基础 URI 哈希分发
在 upstream 块中启用哈希,并在 server 或 location 中调用:
upstream backend_cluster {
hash $request_uri;
server 10.0.1.10:8080;
server 10.0.1.11:8080;
server 10.0.1.12:8080;
}
然后在 server 块中代理请求:
location / {
proxy_pass http://backend_cluster;
proxy_set_header Host $host;
}
此时 /search?q=nginx&page=1 和 /search?page=1&q=nginx 被视为两个不同 URI,可能分到不同后端——若需忽略参数顺序,需先重写 URI 统一格式。
增强可控性:预处理 URI 再哈希
为提升分发合理性,常对 $request_uri 做归一化处理。例如:
- 去掉查询参数:用
$uri替代(仅路径,不含 ? 及之后内容) - 统一小写:通过
map指令转换:map $request_uri $norm_uri {<br> ~^(?<m1>[^?]*)(?:\?(?<m2>.*))?$ ${m1}?${m2};<br>}</m2></m1>
再对$norm_uri哈希(注意:Nginx 本身不支持直接 lowercase URI,需借助 Lua 或外部模块;简单场景可用$uri+$args手动拼接并排序参数) - 排除特定参数(如跟踪用的
utm_*、ts=):用if+set构造净化后的变量,再哈希
适用与慎用场景说明
适合:
– API 级别缓存亲和(如某商品详情页总由同一节点渲染并缓存)
– 后端无状态但需减少跨节点重复初始化(如冷启动耗时服务)
– A/B 测试中按 URL 分流,确保用户多次访问同 URL 始终看到同一版本
慎用:
– URI 参数高度动态(如带时间戳、随机数、签名)会导致哈希完全散列,失去分发意义
– 后端节点频繁扩缩容,普通 hash 会造成大量 URI 重映射,建议加 consistent 关键字
– 需要按用户或设备分流时,$request_uri 不含身份信息,应改用 $cookie_uid 或 $http_x_forwarded_for










