7.3.5 会话保持与灰度发布

本节围绕 Nginx 反向代理与负载均衡中的会话保持灰度发布展开,给出原理草图、配置示例、验证命令、排错方法与练习,确保可落地。

一、原理草图(会话保持 + 灰度发布)

文章图片

二、会话保持(Session Persistence)

1) 基于 IP 的保持(ip_hash)
适用用户 IP 稳定、NAT 影响较小的场景。
配置文件 /etc/nginx/conf.d/app.conf

upstream app_upstream {
    ip_hash;                 # 按客户端 IP 取 hash,固定到同一后端
    server 10.0.0.11:8080;
    server 10.0.0.12:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_upstream;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

验证与解释

# 1) 语法检查
nginx -t

# 2) 重载配置
nginx -s reload

# 3) 多次请求观察后端标识(需后端返回自身ID)
for i in {1..5}; do curl -s http://app.example.com/; done
# 预期:同一客户端多次请求命中同一后端

常见问题排查
- 负载不均衡:大量用户处于同一 NAT 出口时会集中到单节点。
- 登录漂移:用户 IP 变化或切换网络后会话失效。


2) 基于 Cookie 的保持(sticky)
开源 Nginx 需第三方模块或 OpenResty。以下以 OpenResty + sticky 模块为例。

安装(示例:CentOS/AlmaLinux)

# 安装依赖
yum -y install gcc gcc-c++ make pcre-devel zlib-devel openssl-devel

# 下载 OpenResty(含第三方模块能力)
wget https://openresty.org/download/openresty-1.21.4.2.tar.gz
tar -xf openresty-1.21.4.2.tar.gz
cd openresty-1.21.4.2

# 编译安装(示例路径 /usr/local/openresty)
./configure --prefix=/usr/local/openresty \
            --with-http_ssl_module
make -j$(nproc) && make install

配置文件 /usr/local/openresty/nginx/conf/conf.d/app.conf

upstream app_upstream {
    sticky cookie srv_id expires=1h domain=.example.com path=/;
    server 10.0.0.11:8080;
    server 10.0.0.12:8080;
}

server {
    listen 80;
    server_name app.example.com;
    location / { proxy_pass http://app_upstream; }
}

验证与解释

# 查看返回的 Set-Cookie
curl -I http://app.example.com/
# 预期:响应头包含 Set-Cookie: srv_id=...

# 带 Cookie 再次访问,命中同一后端
curl -s -H "Cookie: srv_id=xxxx" http://app.example.com/

常见问题排查
- Cookie 不生效:检查域名、路径、SameSite、Secure。
- 模块不可用:确认 sticky 模块是否编译进 Nginx,查看:

/usr/local/openresty/nginx/sbin/nginx -V 2>&1 | grep -i sticky

3) 应用层会话共享(Redis)
适用于无状态化改造,避免强绑定。

参考架构

文章图片

排错要点
- Redis 连接池超时、网络抖动会导致全体会话异常。
- 通过监控 Redis QPS、连接数与慢查询定位问题。


三、灰度发布(Canary Release)

1) 基于权重的灰度
适合无状态服务,逐步调整流量。

配置文件 /etc/nginx/conf.d/canary.conf

upstream app_upstream {
    server 10.0.0.11:8080 weight=9;  # v1
    server 10.0.0.12:8080 weight=1;  # v2
}

server {
    listen 80;
    server_name app.example.com;
    location / { proxy_pass http://app_upstream; }
}

验证命令

# 模拟 100 次请求统计命中(后端需返回版本号)
for i in {1..100}; do curl -s http://app.example.com/; done | sort | uniq -c
# 预期:v2 约占 10%

2) 基于路径/子域名灰度
适合功能隔离或内部测试。

upstream app_v1 { server 10.0.0.11:8080; }
upstream app_v2 { server 10.0.0.12:8080; }

server {
    listen 80;
    server_name app.example.com;

    location /v2/ {
        proxy_pass http://app_v2;
    }
    location / {
        proxy_pass http://app_v1;
    }
}

3) 基于 Header/Cookie 精准灰度
适合指定用户验证。

map $http_x_gray $backend {
    default app_v1;
    "true"  app_v2;
}

upstream app_v1 { server 10.0.0.11:8080; }
upstream app_v2 { server 10.0.0.12:8080; }

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://$backend;
    }
}

验证命令

# 普通请求走 v1
curl -s http://app.example.com/

# 灰度请求走 v2
curl -s -H "X-Gray: true" http://app.example.com/

四、发布与回滚操作示例(含命令解释)

# 1) 修改配置,提升 v2 权重(编辑 /etc/nginx/conf.d/canary.conf)
# 2) 语法检查
nginx -t

# 3) 重载生效
nginx -s reload

# 4) 回滚:将 v2 权重调回 0 或移除
# 5) 再次检查与重载
nginx -t && nginx -s reload

五、排错清单(快速定位)
- 灰度流量不准:检查 upstream 权重是否生效,确认 Nginx 是否已 reload。
- 会话漂移:检查是否混用 ip_hash 与灰度权重导致跨版本;建议会话存储共享。
- 后端不可用:确认健康检查、端口、ACL、防火墙;查看:

tail -f /var/log/nginx/error.log

六、练习
1) 配置 ip_hash 并验证同一客户端命中一致后端。
2) 将灰度权重从 1% 逐步调到 20%,观察指标变化。
3) 使用 Header 灰度,将指定账号请求导向 v2。
4) 模拟 v2 故障,快速回滚并验证业务恢复。