平滑路由的核心是新旧后端共存、请求自然过渡、失败有兜底、变更不中断;Nginx通过map+upstream+proxy_pass+错误处理机制,可在不改代码、不重启、不丢请求前提下实现动态切换。

平滑路由的核心不是“立刻切走”,而是让新旧后端共存、请求自然过渡、失败有兜底、变更不中断。Nginx 本身不自动做“平滑”,但通过合理组合 map、upstream、proxy_pass 和错误处理机制,就能在不改代码、不重启服务、不丢请求的前提下完成动态路由切换。
用 map + 变量实现运行时路由决策
这是最轻量也最灵活的平滑路由方式,适合灰度发布、紧急回滚或按请求特征分流。关键在于把路由逻辑从配置文件中“抽出来”,变成可运行时修改的变量映射。
- 在
http块中定义map,将请求头、参数或 IP 映射为 upstream 名称,例如:map $http_x_release_flag $backend { "v2" "backend_v2"; default "backend_v1"; } - 对应 upstream 必须提前声明,且所有目标后端都处于可用状态:
upstream backend_v1 { server 10.0.1.10:8080; }<br>upstream backend_v2 { server 10.0.2.20:8080; } - 在 location 中直接使用变量:
proxy_pass http://$backend;—— Nginx 每次请求都会实时解析该变量,无需 reload 即可生效 - 配合 systemd 或简单脚本更新请求头(如测试时加
X-Release: v2),就能秒级控制流量走向
按路径或域名做精准分流
适用于接口级迁移或服务拆分场景,特点是规则明确、边界清晰、易于验证。
- 用
location前缀匹配区分新老路径,例如:location ^~ /api/v2/ { proxy_pass http://micro_user; }location /api/ { proxy_pass http://legacy_app; } - 路径匹配顺序很重要:更具体的规则必须放在通用规则之前,否则会被
location /提前截断 - 支持域名级隔离,如
old.api.example.com固定走旧服务,api.example.com默认走新服务,前端无感知,DNS 切换可延后 - 对未覆盖路径,用
error_page 404 = @fallback或return 404明确响应,避免静默转发导致问题难定位
失败自动降级 + 健康检查兜底
平滑不只是“能切”,更是“切不动时还能稳住”。单靠路由规则不够,必须叠加容错能力。
- 开启
proxy_intercept_errors on;,让 error_page 能捕获后端返回的 5xx 错误 - 配置
proxy_next_upstream error timeout http_502 http_503 http_504;,当新服务不可用时自动重试旧服务(前提是 upstream 中已同时定义两套后端) - 为每个 upstream 启用主动健康检查:
upstream backend_v2 {<br> server 10.0.2.20:8080 max_fails=2 fail_timeout=10s;<br> health_check interval=3 fails=2 passes=2;<br>} - 搭配
slow_start=30s(Nginx 1.15.10+),让新上线节点逐步承接流量,避免冷启动冲击
保持上下文 + 连接复用保障稳定性
路由平滑的前提是请求不被意外改写或中断。很多问题其实出在 header 透传和连接管理上。
- 显式设置关键 header:
proxy_set_header Host $host;<br>proxy_set_header X-Real-IP $remote_addr;<br>proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br>proxy_set_header X-Forwarded-Proto $scheme;
- 启用 HTTP/1.1 长连接复用:
proxy_http_version 1.1;<br>proxy_set_header Connection '';<br>keepalive 32;
(避免频繁建连拖垮后端) - 合理设超时,防止慢请求堆积:
proxy_connect_timeout 5s;<br>proxy_send_timeout 30s;<br>proxy_read_timeout 30s;
- reload 配置时确保 graceful:执行
nginx -t && nginx -s reload,旧 worker 继续处理存量请求,新 worker 接管新连接,全程零中断



















