流量染色是金丝雀发布的核心前置环节,通过在请求头、Cookie等注入标识(如X-Business-ID),再利用Nginx的map指令将其映射为上游变量(如$upstream_group),实现无侵入式、动态路由至不同版本服务,从而支撑按用户/业务维度精准灰度。

什么是流量染色与丝雀发布的关联
流量染色是指在请求进入系统时,通过在请求头、Cookie 或参数中注入特定标识(如 business_id),让后续服务能识别并区分不同来源或策略的流量。在 Nginx 中,map 指令可用于将染色标识映射为可被 upstream 或 rewrite 使用的变量,是实现轻量级、无侵入式金丝雀发布的关键一环。
用 map 提取并分类 business_id
Nginx 的 map 指令必须定义在 http 块中,不能放在 server 或 location 内。它支持正则匹配和精确匹配,适合按业务 ID 做灰度分组:
http {
# 将请求头 X-Business-ID 映射为 $upstream_group 变量
map $http_x_business_id $upstream_group {
default "prod"; # 默认走生产集群
~^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$ "canary-v2"; # 匹配 UUID 格式 v4 的测试业务 ID
"biz-1001" "canary-v1";
"biz-1002" "canary-v1";
"biz-test-alpha" "canary-v2";
}
}
说明:
- $http_x_business_id 自动读取请求头 X-Business-ID 的值
- 支持正则(以 ~ 开头)和字符串精确匹配,顺序靠前的规则优先生效
- 匹配结果赋给自定义变量 $upstream_group,后续可用于路由决策
结合 upstream 实现动态后端选择
定义多个 upstream 分组,再在 location 中根据 $upstream_group 选择目标集群:
upstream prod {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
<p>upstream canary-v1 {
server 10.0.2.10:8080 weight=5; # 可叠加权重控制比例
server 10.0.2.11:8080 weight=5;
}</p><p>upstream canary-v2 {
server 10.0.3.10:8080;
server 10.0.3.11:8080;
}</p><p>server {
listen 80;
location / {
proxy_pass <a href="https://www.php.cn/link/db190973a7de5c5c876cba872133442f">https://www.php.cn/link/db190973a7de5c5c876cba872133442f</a>;
proxy_set_header X-Business-ID $http_x_business_id;
proxy_set_header X-Canary-Group $upstream_group;
}
}
关键点:
- proxy_pass 后直接使用变量(如 https://www.php.cn/link/db190973a7de5c5c876cba872133442f)需确保该变量始终为合法 upstream 名称
- 建议配合 proxy_next_upstream 和健康检查,避免单点故障影响染色一致性
- 透传原始 business_id 和当前分组,便于后端日志追踪与链路分析
增强可控性:支持 header + cookie 多源染色
实际场景中,业务 ID 可能来自请求头、Cookie 或 query 参数。可通过组合 map 实现降级 fallback:
# 先尝试从 header 获取,不存在则从 cookie 提取
map $http_x_business_id $raw_business_id {
"" $cookie_business_id;
default $http_x_business_id;
}
<h1>再对 $raw_business_id 做分组映射</h1><p>map $raw_business_id $upstream_group {
default "prod";
"biz-canary-2024" "canary-v2";
~^test-.*$ "canary-v1";
}
这样既兼容 API 调用(带 header)也支持 Web 页面(依赖 cookie),提升染色覆盖范围。注意:
- map 是惰性求值,只在变量首次被引用时执行,性能开销极小
- 所有 map 变量均为字符串类型,不支持嵌套 map,复杂逻辑建议交由 Lua 或网关层处理
- 修改 map 后 reload Nginx 即可生效,无需重启,适合快速迭代灰度策略


















