nginx通过服务发现(如consul/etcd)动态管理上游节点,结合nginx-upsync-module实时更新upstream、lua实现拓扑感知路由、健康检查自动摘除故障节点,确保拓扑变更无损。

不需要克隆拓扑本身,而是让 Nginx 在运行时按需感知并路由到新拓扑节点——核心是把“业务拓扑”映射为可动态注册/注销的服务实例集合,并由 Nginx 通过异步非阻塞机制实时响应变化。
用服务发现驱动动态 upstream
业务拓扑的“动态特征”(如节点增删、权重调整、区域标签、健康状态)不能硬编码在 nginx.conf 里。应交由 Consul 或 etcd 统一管理,每个服务实例以结构化 JSON 形式注册,例如:
[
{"server":"10.10.2.15:9001","weight":8,"zone":"shanghai"},
{"server":"10.10.3.22:9001","weight":5,"zone":"beijing","backup":true}
]
搭配 nginx-upsync-module,Nginx 每 5 秒自动拉取该数据,更新共享内存中的 upstream 状态,整个过程不 reload、不中断连接。
让请求按拓扑特征智能分发
仅动态加载节点还不够,需结合变量与 Lua 脚本实现拓扑感知路由:
- 用
$upstream_addr或自定义 header(如X-Region)提取客户端地域、设备类型等上下文 - 在
init_worker_by_lua_block中预加载拓扑元数据(如 zone→IP 映射表),避免每次请求查 etcd - 用
balancer_by_lua_block实现加权一致性哈希或区域亲和路由:优先选同 zone 节点,降级时才跨 zone
异步健康检查兜住拓扑变更风险
动态上游本身不主动剔除故障节点。必须叠加主动探测:
- 启用
health_check指令,对每个 upstream server 发起 HTTP HEAD 探活(路径可带拓扑标识,如/health?topo=api-v2) - 失败后自动标记为
down,Nginx 的事件循环会在下一次请求调度时跳过它,无需等待超时 - 配合
max_fails=2 fail_timeout=30s,确保瞬时抖动不误判,但真实宕机 30 秒内即隔离
流量切换全程无损的关键点
所谓“无损”,是指拓扑变更期间已有长连接不中断、新请求不打到下线节点、重试不放大压力:
- 所有 upstream server 配置
keepalive 32;,复用连接池,避免频繁建连放大拓扑震荡 - 设置
proxy_next_upstream error timeout http_503+proxy_next_upstream_tries 2,单次失败快速切到备用节点 - etcd 中删除某节点后,Nginx 最多延迟 5 秒(upsync_interval)感知;期间若该节点已不可达,健康检查会提前将其摘除











