OpenResty是实现全异步、非阻塞后端域名动态解析与切换的最成熟平台,因其可通过lua-resty-dns在请求路径中主动发起异步DNS查询、支持多源兜底与SRV记录解析,而Nginx原生resolver仅支持懒加载+定时刷新、无法实时响应变更或条件化解析。

要实现后端域名的动态解析与切换,且要求全异步、非阻塞,核心在于绕开 Nginx 原生 resolver 的轮询更新机制(它本质是定时重查,非实时响应),转而用 Lua 在请求路径中主动发起 DNS 查询,并缓存结果。OpenResty 是目前最成熟可行的落地平台。
为什么不能只靠 Nginx 的 resolver?
Nginx 的 resolver 指令虽支持域名解析,但它是“懒加载 + 定时刷新”模式:
- 首次解析发生在 proxy_pass 第一次使用变量时,之后按
valid=30s缓存,期间所有请求共享同一 IP - 不感知后端真实健康状态,IP 变更后需等待缓存过期才能更新
- 无法基于子域名、请求头、地理位置等条件做差异化解析
- 不支持 SRV、TXT 等记录类型,也不能做解析失败降级或重试逻辑
用 Lua-resty-dns 实现真正动态解析
借助 lua-resty-dns 库(OpenResty 内置),可在每个请求中异步发起 DNS 查询,全程不阻塞 worker 线程:
- 使用
resolver:new{...}创建 DNS 客户端,指定上游 DNS(如8.8.8.8或内网 CoreDNS) - 调用
r:query(domain, {qtype = r.TYPE_A})发起 A 记录查询,返回协程友好的结果 - 配合
ngx.shared.DICT缓存解析结果(带 TTL),避免高频重复查询 - 可嵌入
access_by_lua*或set_by_lua*阶段,在路由前完成地址决策
典型场景:按子域名自动解析服务实例
例如请求 order-api.prod.example.com,需解析为对应 Kubernetes Service 的 DNS 名(如 order-api.prod.svc.cluster.local):
- 用正则从
$host提取order-api.prod - 拼接内部服务域名:
order-api.prod.svc.cluster.local - 查缓存 → 未命中则异步 DNS 查询 → 写入缓存(TTL 对齐服务侧 readiness probe 周期)
- 将解析出的 IP 赋值给
$backend_addr,供proxy_pass http://$backend_addr使用
增强可靠性:失败自动降级与多源兜底
单点 DNS 故障会导致整个解析链路中断。Lua 层可灵活设计容错策略:
- 主 DNS 查询失败时,自动切到备用 DNS(如
114.114.114.114或内网 dnsmasq) - 仍失败则返回预设的静态 fallback IP(如本地 mock 服务或维护页)
- 支持 SRV 记录解析,按权重/优先级选取后端(适合 gRPC 或自定义协议服务发现)
- 结合健康检查(如 ping 或 HTTP HEAD 探活),剔除不可用节点,再做负载选择











