nginx灰度发布不可用rewrite,因其仅支持url重写或跳转,无法实现基于header/cookie/ip等特征的精准路由;应使用map指令提取请求特征,结合upstream分组与proxy_pass动态转发至新/旧版本后端。

Nginx 本身不直接用 rewrite 规则实现灰度发布——rewrite 主要用于 URL 重写或跳转(如 301/302),而灰度发布本质是请求路由分发,需依赖 map、upstream 和条件判断(如 if 或变量控制)来完成流量分流。若强行用 rewrite 做灰度,容易导致跳转暴露路径、破坏会话、丢失请求体,且无法支持 header/Cookie/IP 等精细控制,不推荐也不实用。
真正平滑灰度的关键,在于在 proxy_pass 阶段动态选择后端集群,而非重写 URL。下面讲清楚几个核心要点:
为什么 rewrite 不适合做灰度
-
rewrite发生在请求处理早期,常触发外部重定向(HTTP 302),用户可见地址变化,破坏单页应用(SPA)、中断 POST 请求、丢失原始 body; - 无法保留灰度上下文(如某用户已进入灰度,下次请求仍需命中同一版本),
rewrite无状态,难维持一致性; - 不支持按权重、Header、Cookie 等多维条件组合判断,灵活性差。
正确做法:用 map + upstream + proxy_pass 实现灰度路由
这才是 Nginx 中稳定、高效、生产可用的方式。常见三类典型场景:
-
基于特定 IP 或 IP 段的灰度
map $remote_addr $backend_group { default "stable"; 10.8.102.69 "canary"; # 内网测试机 ~^192\.168\.99\.(1|2)\d+ "canary"; # 匹配 192.168.99.1xx/2xx } upstream stable { server 192.168.1.100:80; } upstream canary { server 192.168.1.101:80; } server { listen 80; location / { proxy_pass http://$backend_group; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } -
基于 Cookie 的灰度(如 is_gray=1)
map $http_cookie $backend_group { ~*is_gray=1 "canary"; default "stable"; } -
组合策略:优先匹配灰度标识,剩余流量按权重分配
map $http_cookie $route_by_cookie { ~*version=v2 "canary"; default ""; } map $route_by_cookie $backend_group { "" $default_backend; # fallback to weighted group "canary" "canary"; } upstream default_backend { server 192.168.1.100 weight=95; server 192.168.1.101 weight=5; # 新版先跑 5% } upstream canary { server 192.168.1.101:80; }
架构升级中如何“平滑”落地
- 所有灰度规则统一收口在 Nginx 入口层,业务服务无需改代码;
- 新旧服务并行部署,Nginx 动态切流,零停机;
- 可配合健康检查(
max_fails/fail_timeout)自动剔除异常节点; - 修改配置后只需
nginx -s reload,毫秒级生效,无需重启进程。
不复杂但容易忽略:灰度期间务必开启 $request_id 日志、记录 $backend_group 变量,方便问题定位与流量回溯。











