记录一下那天晚上的排查过程。nginx 1.24 上想按请求头里的灰度标记分流,map 里先写了 default 再写具体条件,reload 之后带 x-gray: v2 的请求全部落到旧集群,access.log 里 upstream 一直是 old_pool。

刚开始盯着「location 里又重新写死了 proxy_pass,map 出来的变量根本没用上」,折腾了半个多小时,排掉了。

原因不止一个,得分开看。map 的匹配是整串比较,正则没加 ~* 时区分大小写,v2 和 V2 对不上。少数情况下是变量名写成了 $http_x_gray 之外的拼法,取到的始终是空串。

不容易想到的是,灰度条件写在 server 级,内层 location 的 upstream 把它覆盖了。

第一件事是把变量实际取到的值打出来

curl -s -H 'x-gray: v2' -D - -o /dev/null http://127.0.0.1/ | grep -i gray

接着看 map 块和引用它的位置

nginx -T | grep -n -A8 'map .*gray'

再往下改成不区分大小写并补齐默认分支

printf '%s
' 'map $http_x_gray $pool {' '    default old_pool;' '    ~*v2    new_pool;' '}' > /etc/nginx/conf.d/gray.conf

reload 后按 upstream 名核对

nginx -t && nginx -s reload && tail -200 /var/log/nginx/access.log | grep -o 'upstream=[^ ]*' | sort | uniq -c

改完先别撤,确认这几项。带 x-gray: v2 的请求落到 new_pool,不带头的仍走 old_pool,两边比例和灰度计划一致。

容易忽略的是,map 只能放在 http 块里,塞进 server 里 nginx -t 就会报错;调试分流最省事的办法是临时 add_header 把变量值回显到响应头。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189