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 故障,快速回滚并验证业务恢复。