在 Nginx 中实现基于权重的灰度发布,最直接的做法是在 upstream 模块中为不同后端服务器设置 weight 参数。这种方式适合无状态服务的简单按比例分流,但需注意会话保持与验证方法的配套配置。
先说结论:通过 upstream 权重配置可以实现基础的流量按比例分发,但默认不支持会话保持,且验证分流效果需后端配合或查看日志。
- 适合:无状态服务、HTTP 短连接场景、新版本小流量随机测试
- 先准备:确认后端服务健康状态、备份当前配置文件、规划好权重比例、配置后端返回标识或 Nginx 日志格式
- 验收:通过批量请求统计后端标识分布、分析 Nginx 访问日志中的 $upstream_addr 字段
核心配置步骤
1. 编辑配置文件,通常位于 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/ 下的站点文件。
2. 定义 upstream 块,设置 weight 参数。权重越高,分配到的请求越多:
upstream backend {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=1;
}
3. 在 server 块中引用 upstream:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
配置生效与重载
修改配置后必须先检查语法,再平滑重载,避免服务中断:
nginx -t && nginx -s reload
若 nginx -t 报错,请根据提示检查括号匹配或分号缺失。
验证分流是否生效
权重配置生效后,需通过以下两种方式进行验证,确保流量按预期分布。
方式一:后端服务返回标识
前提需要后端服务能在响应中返回自身标识(如 IP 或主机名)。以下以 Java Spring Boot 为例,在 Controller 中返回本地主机名:
@RestController
public class InfoController {
@GetMapping("/info")
public String getInfo() {
return InetAddress.getLocalHost().getHostName();
}
}
配置完成后,使用循环请求配合统计命令观察分布情况。例如发送 100 个请求:
for i in {1..100}; do curl -s http://your-domain.com/info; echo; done | sort | uniq -c
输出结果应大致符合权重比例(如 3:1)。
方式二:通过 Nginx 访问日志验证
若无法修改后端代码,可通过 Nginx 日志中的 $upstream_addr 字段验证。需在 http 块中配置自定义日志格式:
log_format upstream_log '$remote_addr - $upstream_addr - $request';
access_log /var/log/nginx/access.log upstream_log;
重载配置产生流量后,使用 awk 统计日志中不同后端 IP 的出现次数:
awk '{print $3}' /var/log/nginx/access.log | sort | uniq -c
字段位置取决于 log_format 定义,请根据实际情况调整 awk 列号。
会话保持与权重冲突解决方案
默认权重轮询不保证同一用户请求落到同一台服务器。涉及登录态的服务需配合会话保持方案,但需注意以下冲突:
- ip_hash 限制:原生 Nginx 开启
ip_hash后,weight参数会失效,流量将强制按 IP 哈希分配,无法实现权重灰度。 - 替代方案:若需同时支持权重分流和会话保持,建议使用第三方模块
nginx-upstream-sticky-module。
配置示例(需编译支持 sticky 模块):
upstream backend {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=1;
sticky_cookie srv_id expires=1h domain=.your-domain.com path=/;
}
该方案通过 Cookie 实现粘性会话,同时保留权重分配能力。
灰度发布场景说明
权重分流属于“随机灰度”,流量分配不可控(无法指定特定用户)。若需基于用户特征(如 Header、Cookie、URI)进行精细灰度,需配合 map 指令或 if 判断:
map $http_x_canary $backend_version {
default "backend_v1";
"true" "backend_v2";
}
upstream backend_v1 { server 192.168.1.10:8080; }
upstream backend_v2 { server 192.168.1.11:8080; }
server {
location / {
proxy_pass http://$backend_version;
}
}
常见坑与排查
- 长连接影响:如果客户端保持长连接,请求分布可能不会严格符合权重比例,因为连接复用会导致请求集中在少数连接上。验证时建议使用短连接或清除 Keep-Alive。
- 后端健康检查:修改权重后必须确保新后端服务已启动并健康,否则 Nginx 会将流量转发至故障节点导致 502 错误。建议配置
max_fails和fail_timeout。 - 配置生效:修改后必须执行 reload,且确保新配置文件语法无误。
- 日志权限:验证日志时确保当前用户有权限读取
/var/log/nginx/access.log。
参考来源
- Nginx 官方文档 - ngx_http_upstream_module - https://nginx.org/en/docs/http/ngx_http_upstream_module.html
- Nginx Sticky Module - https://github.com/nginx-modules/nginx-upstream-sticky-module