nginx的split_clients模块通过一致性哈希实现无状态a/b测试分流,基于$remote_addr等变量计算确定性哈希值并按整数百分比区间映射分组,确保同一用户始终命中相同版本,需reload生效且不支持动态调权。

使用 Nginx 的 split_clients 模块可以在反向代理层实现轻量、无状态的 A/B 测试流量分流,无需业务代码介入,适合灰度发布或功能对比实验。
理解 split_clients 的核心机制
split_clients 是 Nginx 内置的变量哈希分流模块,它基于指定变量(如 $remote_addr、$cookie_uid 或自定义 header)计算一致性哈希值,映射到预设的百分比区间,从而将请求稳定分配到不同后端组。关键特性包括:
- 分流结果是确定性的:同一输入变量每次计算结果一致,保障用户会话“粘性”
- 不依赖外部存储或状态同步,适合横向扩展的代理集群
- 仅支持整数百分比划分(总和必须为 100),不支持动态权重调整(需 reload 配置)
- 变量值为空时默认归入第一个分支(建议显式处理空值)
基础配置示例:按用户 IP 分流
以下配置将 70% 流量导向 v1 版本,30% 导向 v2 版本:
split_clients "$remote_addr" $backend_version {
70% "v1";
* "v2";
}
<p>upstream backend_v1 {
server 10.0.1.10:8080;
}</p><p>upstream backend_v2 {
server 10.0.1.20:8080;
}</p><p>server {
listen 80;
location / {
proxy<em>pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a></em>$backend_version;
proxy_set_header Host $host;
}
}</p>
注意:$remote_addr 在有前置 CDN 或 LB 时可能失真,此时应改用 $http_x_real_ip 或可信 header,并确保在 real_ip 指令中已正确配置可信网段。
进阶用法:按 Cookie 或 Header 精准控制
若需按用户 ID 或实验分组标识分流(更符合 A/B 测试语义),可结合 cookie 或自定义 header:
# 优先取实验 cookie, fallback 到 uid cookie,再 fallback 到 IP
set $ab_key "";
if ($cookie_exp_id != "") {
set $ab_key $cookie_exp_id;
}
if ($ab_key = "" && $cookie_uid != "") {
set $ab_key $cookie_uid;
}
if ($ab_key = "") {
set $ab_key $remote_addr;
}
<p>split_clients "$ab_key" $ab_group {
50% "control";
50% "test";
}</p>
这样能保证同一用户始终落在同一分组,避免体验割裂。注意 Nginx 的 if 在 location 外使用是安全的,但不要在 location 内嵌套 if 做复杂判断。
验证与调试技巧
分流逻辑上线前建议通过日志确认效果:
- 在 log_format 中加入
$ab_group或$backend_version变量 - 用 curl 模拟不同 IP 或 cookie 请求,检查响应头或 upstream 地址是否符合预期
- 统计 access log 中各分组占比(如用 awk + sort + uniq),验证是否接近设定比例
- 若发现偏差显著(如 90/10 实际变成 95/5),可能是哈希分布不均,可尝试加盐(如
"$ab_key-2024")改善散列效果
不复杂但容易忽略:reload 配置后,旧 worker 进程仍按旧规则处理长连接,新连接才走新规则,因此观察效果需等待连接自然切换或主动重启 worker。










