Nginx 中可通过 map 模块清洗自定义请求头(如 X-User-ID),再用 hash 指令(启用 consistent)实现类 ip_hash 的一致性哈希路由,支持兜底至 $remote_addr,确保键稳定、防漂移。
在 Nginx 中,ip_hash 本身只支持基于客户端真实 IP 做哈希,无法直接使用自定义请求头(如 X-Real-IP、X-Forwarded-For 或业务标识头如 X-User-ID)作为哈希键。但可以通过 map 模块 + hash 指令(而非 ip_hash)实现更灵活的“类 IP Hash”行为——即提取特定头部,做一致性哈希分发。
map 模块用于将一个变量(如请求头)映射为另一个变量,支持正则匹配、默认值和空值处理,是安全提取头部的前提。
例如,想用 X-User-ID 作为哈希依据,但该头可能缺失、为空或含非法字符:
map $http_x_user_id $upstream_key {default"";"" "";"~^([a-zA-Z0-9_-]{4,32})$"$1;# 只接受 4–32 位字母数字下划线}
这样就得到一个清洗后、可信赖的 $upstream_key,避免空值或恶意输入导致哈希紊乱。
在 upstream 块中不能用 ip_hash 配合自定义键,但可以用 hash 指令(需启用 ngx_http_upstream_module 的 hash 功能):
hash 支持变量)hash 默认启用一致性哈希(ketama),比简单取模更抗节点增减ip_hash 的“客户端固定到一台”,必须保证键稳定且非空配置示例:
upstream backend {hash $upstream_key consistent;server 10.0.1.10:8080;server 10.0.1.11:8080;server 10.0.1.12:8080;}
注意:consistent 参数启用 ketama 一致性哈希,比默认取模方式更均衡、更稳定。
业务头不可靠时,可组合多个来源,优先用自定义头,退化到 $remote_addr:
map $http_x_user_id $hash_key {"" $remote_addr;default $http_x_user_id;}或更严谨地(过滤空格、多值):map $http_x_forwarded_for $client_ip { ~^(d+.d+.d+.d+)$1; default $remote_addr; }
map $http_x_user_id $upstream_key { ""$client_ip; default $http_x_user_id; }
这样既尊重业务标识,又保障无头请求仍能稳定路由,避免会话漂移。
上线前建议加临时日志确认键生成逻辑是否符合预期:
add_header X-Upstream-Key "$upstream_key"; 返回键值(仅测试环境)log_format 记录 $upstream_key 和后端地址,观察分布是否均匀$http_* 变量名全小写,且连字符转下划线(X-User-ID → $http_x_user_id)不复杂但容易忽略细节,关键是 map 清洗 + hash 代替 ip_hash + 合理 fallback。