Nginx原生不支持proxy_pass动态变量,需用OpenResty的Lua模块实现:set_by_lua_block配合resolver适用于简单域名/IP路由;balancer_by_lua_block接管负载均衡更健壮,支持权重、健康检查;结合Redis可实现中心化路由控制,需注意resolver配置、变量作用域及超时降级。

直接在 proxy_pass 前用变量拼接(比如 proxy_pass http://$backend)是行不通的,除非该变量已在 upstream 或 server 块中静态定义。Nginx 原生不支持运行时动态解析并转发到任意变量地址——必须借助 OpenResty 的 Lua 模块,在特定阶段介入请求处理流程。
用 set_by_lua* 配合 resolver 实现基础动态地址
适用于后端是域名或固定 IP:Port、且不需要复杂负载逻辑的场景:
- 先在
http块顶部配置 DNS 解析器:resolver 8.8.8.8 valid=30s;(必须有,否则变量 proxy_pass 不生效) - 在
location中用set_by_lua_block计算目标地址,存入 Nginx 变量,例如:set_by_lua_block $target {<br> local version = ngx.var.headers["x-deploy-version"]<br> if version == "v2" then<br> return "api-v2.example.com:8080"<br> else<br> return "api-v1.example.com:8080"<br> end<br>} - 再写
proxy_pass http://$target;—— 此时 Nginx 会调用 resolver 解析该变量值
用 balancer_by_lua_block 完全接管后端选择
这是更健壮、生产推荐的方式,能支持权重、健康检查、一致性哈希等高级能力,且不依赖 resolver:
- 定义一个空 upstream(仅占位,server 行可写任意假地址):
upstream dynamic_backend { server 127.0.0.1:1; } - 在 location 中
proxy_pass http://dynamic_backend; - 通过
balancer_by_lua_block在负载均衡阶段动态选节点:balancer_by_lua_block {<br> local peers = {"10.0.1.10:8080", "10.0.1.11:8080"}<br> local idx = ngx.var.arg_uid % #peers + 1<br> balancer.set_current_peer(peers[idx])<br>} - 注意:此方式下 upstream 原有重试、keepalive 等配置失效,需在 Lua 中自行实现
结合 Redis 实现中心化路由控制
把路由规则从 Nginx 配置中剥离,由外部系统统一管理:
- 用
resty.redis模块在access_by_lua_block或balancer_by_lua_block中查 Redis:
key 如route:api或upstream:payment-v2,值为10.0.2.5:9000或svc-payment.prod.svc.cluster.local:80 - 查询结果直接用于
balancer.set_current_peer();若是域名,仍需配合resolver - 建议设置 Redis 超时 ≤ 100ms、失败时 fallback 到默认后端,避免阻塞请求
注意事项与避坑点
几个容易出错的关键细节:
-
set_by_lua*设置的变量只能在当前请求生命周期内使用,不能跨 location 或子请求继承 - 变量
proxy_pass必须搭配resolver,且目标必须是完整 host:port 格式(不能只有 host) -
rewrite_by_lua*阶段修改 URI 后,不能再用set_by_lua*改变$target,顺序很重要 - 若后端是 Kubernetes Service 域名,确保 resolver 能访问集群 DNS(如
resolver 10.96.0.10 valid=5s;)


















