Nginx 动态更新 upstream 需使用 nginx-upsync-module 等支持运行时变更的模块,通过 Consul/etcd 自动拉取配置并热更新至共享内存,无需 reload;配合健康检查与可观测机制保障稳定性。

想让 Nginx 网关在不重启、不重载的前提下动态更新上游(upstream)服务列表?关键在于绕过传统 upstream 块的静态编译限制,改用支持运行时变更的动态上游模块。目前最成熟、生产验证过的方案是 nginx-upstream-dynamic(基于 OpenResty 的 Lua 实现)或商业版 Nginx Plus 的 upstream_conf 接口。开源生态中,更轻量且广泛采用的是基于 Consul + nginx-upsync-module 或 etcd + nginx-upsync-module 的组合。
选对模块:开源场景推荐 nginx-upsync-module
nginx-upsync-module 是由微博开源的第三方模块,支持从 Consul、etcd 等服务发现后端自动拉取 upstream 配置,并热更新到内存中,无需 reload。它不修改 Nginx 核心逻辑,而是通过定时拉取 + 共享内存(shared memory zone)实现平滑切换。
- 编译时需显式添加:
--add-module=/path/to/nginx-upsync-module - 依赖对应的服务发现组件(如 etcd v3 API),确保 Nginx 能网络访问其 endpoint
- 不兼容官方 Nginx 的某些高级 upstream 指令(如
queue),但覆盖 weight、max_fails、fail_timeout 等常用参数
配置示例:用 etcd 驱动动态 upstream
以下是一个最小可运行配置片段,定义名为 backend_api 的动态上游:
upstream backend_api {
server 127.0.0.1:8080; # 占位 server,实际不生效
upsync 127.0.0.1:2379/v3/kv/range upsync_timeout=6m upsync_interval=5s upsync_type=etcd_v3;
upsync_dump_path /var/run/nginx/upstream_api.conf;
}
说明:
-
upsync指向 etcd v3 的 kv 查询接口(需提前将上游列表以 JSON 格式写入 etcd,例如 key 为/upstreams/backend_api,value 为[{"server":"10.0.1.10:8000","weight":5},{"server":"10.0.1.11:8000","weight":5}]) -
upsync_dump_path是故障兜底:当 etcd 不可用时,Nginx 启动时会从该本地文件恢复上次成功同步的 upstream 配置 - 所有变更只需更新 etcd 中的 JSON 数据,Nginx 在数秒内自动感知并生效,无连接中断
配合健康检查:避免把流量打到已下线节点
动态上游本身不带主动探活能力,需叠加 health_check 机制。推荐两种方式:
- 复用 Nginx 官方
health_check指令(需开启stream或httphealth check 模块),对 upstream 中每个 server 发起周期性 HTTP/TCP 探测 - 由服务注册中心(如 Consul)统一做健康检查,并只将通过检查的实例写入 KV 存储——Nginx 只负责消费,职责分离更清晰
- 注意:upsync 模块自身支持
down字段标记临时下线,可在 JSON 中设"down": true,模块会自动跳过该节点
可观测与排障要点
动态 upstream 运行在后台,出问题时不易定位。建议落地前打通基础可观测链路:
- 启用
upsync_status指令暴露监控端点(如location = /upsync_status { upsync_status; }),可查看当前加载的 server 列表、同步状态、失败次数 - 打开
error_log的notice或info级别,关注upsync: sync upstream和upsync: failed to fetch日志 - 定期校验
upsync_dump_path文件内容是否与 etcd 一致,防止 dump 文件陈旧导致恢复异常

















