nginx四层tcp代理通过hash $remote_addr consistent;实现客户端ip一致性哈希绑定,确保同一ip始终转发至同一后端;需置于stream的upstream块内,经代理时应启用proxy protocol并改用$proxy_protocol_addr。

Nginx 的四层 TCP 代理(即 stream 块)本身不解析 HTTP 协议,因此无法直接使用 $remote_addr 或 proxy_set_header 等七层机制。但可通过 hash 指令结合 upstream 的一致性哈希策略,将客户端 IP 映射到固定后端服务器,实现“IP 绑定”效果——即相同客户端 IP 总被转发到同一台上游节点。
1. 使用 hash 指令对 client_addr 做一致性哈希
在 stream 上下文中,hash 指令支持变量(如 $remote_addr),并可启用 consistent 参数实现 Ketama 一致性哈希,显著提升节点增减时的映射稳定性。
示例配置:
stream {
upstream backend_tcp {
hash $remote_addr consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}
server {
listen 12345;
proxy_pass backend_tcp;
proxy_timeout 1s;
proxy_responses 1;
}
}
-
$remote_addr 是 stream 模块中唯一可靠标识客户端真实 IP 的变量(前提是未经过多层代理;若经 LVS 或云 LB,需用
proxy_protocol配合) - consistent 启用一致性哈希,避免增删节点时大量连接重散列
- 不建议用
$binary_remote_addr(stream 中不可用),该变量仅限 http 块
2. 处理代理链中的真实 IP 透传
若 Nginx 前有 TCP 负载均衡器(如阿里云 SLB、AWS NLB 或自建 LVS),原始客户端 IP 会被覆盖为上一跳地址。此时必须启用 PROXY 协议:
- 上游负载器需开启 PROXY protocol v1 发送源 IP
- Nginx stream 需配置
proxy_protocol on;解析头部 - 再通过
$proxy_protocol_addr替代$remote_addr参与哈希
修正后的 upstream 示例:
upstream backend_tcp {
hash $proxy_protocol_addr consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
对应 server 块需启用解析:
server {
listen 12345 proxy_protocol;
proxy_pass backend_tcp;
}
3. 注意事项与常见问题
- IPv6 兼容性:Nginx 1.19.0+ 支持 IPv6 地址参与 hash;旧版本建议统一转为 IPv4-mapped 或做预处理
- 短连接抖动:TCP 连接频繁新建时,因每次连接独立哈希,仍可能落在不同后端;若需会话级绑定,应确保应用层维持长连接或使用连接池
-
权重无效:启用
hash后,weight参数被忽略;如需加权哈希,需升级至 Nginx Plus 或改用第三方模块(如 nginx-sticky-module) -
调试方法:启用
error_log /path/to/log debug;并观察stream realip和stream upstream日志段,确认哈希输入值与选中 server
4. 替代方案对比:ip_hash vs hash
注意:ip_hash 是 http 块专用指令,在 stream 块中完全不可用。唯一等效机制就是 hash $remote_addr consistent。
- 若不用
consistent,默认为普通取模哈希,节点变化时映射关系剧烈震荡 - 若想按端口+IP 绑定(更精细),可用
hash "$remote_addr:$remote_port" consistent,但会显著增加后端分散度 - 不推荐用
$server_addr或$time_iso8601等非客户端稳定变量,无法保证绑定效果











