一、前言
在传统服务器部署中,我们更新后端服务通常是:
- 停止旧容器
- 启动新容器
这个过程会直接导致:
- 发布期间接口 502 Bad Gateway
- 用户访问中断、前端报错
- 监控告警、接口超时失败
即使使用'先启动临时实例、再关闭旧实例',如果 Nginx 配置、健康检查、脚本逻辑不正确,依然会出现各种诡异问题:发布瞬间 502、脚本卡死、接口不通等。
本文带你从零搭建一套真正可用、无感知、零停机的发布方案。
二、遇到的典型问题(你大概率也踩过)
直接重启容器 → 必现 502
原因:主容器重启期间,Nginx 仍在转发请求,无可用后端服务。
加了 backup 副本 → 依然偶尔 502
upstream ring_servers {
server ring:8080;
server ring_temp:8080 backup;
}
原因:
- backup 只有主节点完全挂掉才会切换
- Nginx 没有失败重试机制,重启瞬间仍会丢请求
- 健康检查不及时
发布脚本检查接口 → 直接卡死
原因:
- 接口未就绪时,curl 阻塞等待
- 检查公网入口受 Nginx 影响,无法真实判断服务状态
健康检查接口被登录拦截 → 返回 401
原因:健康接口走了登录校验,HTTP 200 但业务码 401,导致脚本误判。
三、整体零停机发布方案(通用架构)
核心思路:双实例兜底 + Nginx 自动重试 + 安全发布脚本
- 正常运行:主服务提供流量
- 发布时:先启动临时副本 → 等待就绪 → 重启主服务 → 主服务就绪 → 关闭临时副本
- Nginx:自动转发到可用节点,用户无感知
四、第一步:Nginx 配置(最关键,解决 502)
- upstream 负载均衡配置
upstream ring_servers {
least_conn; # 主服务
server ring:8080 max_fails=1 fail_timeout=1s;
# 临时服务(发布兜底,backup 模式)
server ring_temp:8080 max_fails=3 fail_timeout=30s backup;
# 核心:出错自动重试下一个节点,用户看不到 502
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2;
keepalive 32;
}
- 代理通用配置
proxy_connect_timeout 10s;
proxy_send_timeout 10s;
proxy_read_timeout 30s;
proxy_buffering on;
说明:proxy_next_upstream 是零停机的灵魂,请求失败会自动重试下一个节点。
五、第二步:docker-compose.yml 配置
只保留核心结构,可直接套用:
version: "3.9"
services:
# 主服务
ring:
[, , , , , , , ]

