nginx stream模块本身不支持灰度发布,需通过geo/map实现ip哈希路由、msec随机分流或auth_http对接外部服务动态决策,并配合proxy protocol透传客户端真实ip。

Nginx 的 stream 模块支持 TCP/UDP 流量的四层代理,但本身不内置“灰度发布”逻辑——它没有像 HTTP 模块中 map + split_clients 或请求头匹配那样的原生灰度能力。要实现 TCP 灰度,核心思路是:**利用客户端特征(如 IP 地址)做一致性哈希或条件路由,将流量按规则分发到不同后端集群**。下面分步说明可行方案。
基于客户端 IP 的一致性哈希灰度
适用于客户端 IP 稳定、且希望同一客户端长期固定访问灰度或稳定版本的场景(如数据库连接、游戏服务器接入)。Nginx stream 支持 hash 指令配合 ip_hash 变量(注意:stream 模块中不能用 $remote_addr 直接 hash,需借助 geo 或 map 预处理)。
- 先用
geo指令标记灰度 IP 段(例如将 192.168.10.0/24 划为灰度用户):
geo $is_gray {
default 0;
192.168.10.0/24 1;
2001:db8::/64 1;
}- 在
stream块中定义 upstream,并用hash+ 条件变量控制流向:
upstream backend_stable {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
}
<p>upstream backend_gray {
server 10.0.2.10:8080;
server 10.0.2.11:8080;
}</p><p>server {
listen 9000;
proxy_pass $upstream_name;</p><h1>根据 $is_gray 动态选择 upstream</h1><p>set $upstream_name "backend_stable";
if ($is_gray) {
set $upstream_name "backend_gray";
}
}</p>注意:stream 模块中 if 仅支持有限变量($geo_*, $map_*, $variable),且 set 在 stream 中需配合 stream_geo 或 stream_map 使用;更稳妥方式是用 map 预计算:
stream {
map $is_gray $upstream_name {
0 "backend_stable";
1 "backend_gray";
}
<p>upstream backend_stable { ... }
upstream backend_gray { ... }</p><p>server {
listen 9000;
proxy_pass $upstream_name;
}
}</p>基于连接时间或随机因子的简易灰度分流
若无客户端标识,可借助 Nginx 内置变量(如 $msec)做伪随机分流(适合测试阶段小流量验证):
- 用
map将毫秒级时间末位映射为 0–9,再按阈值切分(如 0–1 表示 20% 灰度):
map $msec $gray_ratio {
~\.([0-9])$ $1;
}
<p>map $gray_ratio $upstream_name {
0 "backend_gray";
1 "backend_gray";
default "backend_stable";
}</p>说明:该方法非严格均匀,但无需外部依赖,适合快速验证灰度服务连通性与基础逻辑。
结合外部服务实现动态灰度策略
真正生产可用的灰度需支持运行时开关、权重调整、用户标签匹配等。此时应让 Nginx stream 作为透明代理,把决策交给外部服务:
- 使用
auth_http指令(stream 模块支持)在连接建立前调用 HTTP 接口判断是否灰度:
upstream auth_server {
server 127.0.0.1:8081;
}
<p>server {
listen 9000;
auth_http <a href="https://www.php.cn/link/7b4318dbdabe25ce0d7c9c876fe24b67">https://www.php.cn/link/7b4318dbdabe25ce0d7c9c876fe24b67</a>;
auth_http_timeout 5s;</p><h1>auth_server 返回 200 + header "X-Upstream: gray" 即走灰度</h1><p>auth_http_header X-Upstream $upstream_name;</p><p>proxy_pass $upstream_name;
}</p>关键点:auth_server 需实现业务逻辑(如查用户白名单、读取配置中心灰度规则、解析 TLS SNI 或 PROXY protocol 中的元数据),并返回标准 HTTP 响应头告知 Nginx 路由目标。
补充:启用 PROXY Protocol 传递原始客户端信息
当 Nginx 前有 LVS、云负载均衡或另一层 Nginx 时,真实客户端 IP 会丢失。开启 PROXY protocol 可透传源地址,确保灰度判断准确:
- 在前端代理(如阿里云 SLB)开启 PROXY v1/v2;
- Nginx stream 的
server块添加:proxy_protocol on;; - 后端服务(如 MySQL、Redis)需支持接收并解析 PROXY protocol,或由中间件(如 HAProxy)中转解析后注入自定义 header(但 stream 层无法加 header,此步需应用层适配)。
若后端不支持 PROXY protocol,可在 stream 中用 realip 模块(需编译进 Nginx)还原 $remote_addr,但 stream 模块对 realip 支持有限,推荐优先使用 PROXY protocol。











