Nginx网关通过OpenResty的Lua脚本按需调用Consul健康服务API动态获取上游节点,结合shared dict缓存与balancer_by_lua_block实现免reload的实时路由;服务名从Host、路径或Header提取,支持容错降级与指标监控。

Nginx 网关通过 Lua 脚本 + Consul 实现自动路由更新,核心思路是:让 Nginx(通常用 OpenResty)在请求处理阶段动态查询 Consul 的服务发现数据,实时生成或刷新上游节点列表,避免手动 reload 配置。这不是“热重载 nginx.conf”,而是运行时动态选 upstream。
Consul 作为服务注册中心提供实时数据
服务实例启动时向 Consul 注册(如 /v1/agent/service/register),健康检查失败时自动剔除。Nginx Lua 不需要监听变更事件,而是按需拉取——更轻量、更可靠。
- 推荐使用 Consul 的 健康服务列表 API:
/v1/health/service/{service_name}?passing=true - 确保 Consul ACL 已配置,Lua 中通过 token 访问(如需)
- 服务名(
service_name)可从请求 Host、URL 路径或 header 中提取,实现多租户或多服务路由
OpenResty + lua-resty-consul 实现动态 upstream
直接在 location 或 access_by_lua_block 中调用 Consul API 获取节点,再用 balancer_by_lua_block 设置转发目标(OpenResty 1.21.4+ 原生支持)。
- 不依赖
nginx.conf静态 upstream 块,所有节点由 Lua 运行时决定 - 使用
lua-resty-http发起异步 HTTP 请求(推荐复用 connection pool) - 结果缓存到 shared dict(如
consul_cache),设置 TTL(如 5s),避免每次请求都查 Consul - 解析返回的 JSON,提取
Service.Address和Service.Port,构建成 IP:Port 列表
路由匹配与服务名提取(关键逻辑)
如何知道当前请求该打到哪个 Consul 服务?常见方式:
-
Host 头映射:请求
api.user.example.com→ 服务名user-api -
路径前缀:请求
/order/xxx→ 服务名order-svc(配合map指令预定义规则) -
Header 指定:如
X-Service-Name: payment(适合灰度或调试)
提取后拼接 Consul 查询 URL,走缓存 → 查询 → 解析 → 负载均衡链路。
容错与降级必须做
Consul 不可用或返回空列表时,Nginx 不能直接 502:
- 缓存中无数据且 Consul 请求失败 → 回退到上一次有效列表(shared dict 中保留 last_known)
- 仍无可用节点 → 返回 503 或跳转到静态兜底页(
rewrite /fallback break) - 对 Consul 请求设超时(connect/read timeout ≤ 300ms),避免阻塞请求流
- 记录日志(
ngx.log)和指标(如用lua-resty-prometheus上报失败次数)
整个流程不依赖外部配置中心推送或文件监听,完全由 Nginx Lua 自主决策,部署简单、扩展性强。只要 Consul 集群稳定,就能支撑千级服务实例的动态路由。


















