核心在于Nginx默认仅启动时解析upstream域名且不刷新,必须用变量式proxy_pass(如proxy_pass http://$backend;)配合同作用域resolver指令(如resolver 8.8.8.8 valid=30s;)才能实现按需动态解析。

排查 proxy_pass 动态解析 IP 缓存过期的问题,核心在于理解 Nginx 默认的 DNS 解析行为:它对 upstream 域名只做一次解析(启动时),后续不自动刷新,除非显式配置 DNS 缓存刷新机制。
确认是否用了静态域名直连 upstream
如果 proxy_pass 直接写死域名(如 proxy_pass http://api.example.com;),且没配 resolver,Nginx 就会在加载配置时解析一次该域名,结果硬编码进内存。后端 IP 变更后,Nginx 仍发请求到旧 IP,表现为连接超时、502 或上游拒绝连接。
- 检查配置中是否有
resolver指令(必须存在才能启用运行时 DNS 解析) - 确认
proxy_pass后跟的是变量(如$backend),而非字面量域名 —— 只有变量形式才触发动态解析 - 查看 error log,搜索
no resolver defined或host not found in upstream等关键报错
验证 resolver 配置是否生效且可访问
启用动态解析需搭配 resolver 和变量式 proxy_pass。常见错误是 resolver 不可用或超时设置不合理。
-
resolver必须在http或server块顶层定义,不能在location内 - 推荐加
valid=30s(如resolver 8.8.8.8 valid=30s;),否则默认缓存 5 分钟,仍可能滞后 - 用
dig api.example.com @8.8.8.8或nslookup确认 resolver 地址可达、能正确返回 A 记录 - 注意:Linux 系统的
/etc/resolv.conf不被 Nginx 使用,必须显式声明resolver
检查 upstream 是否意外绕过了 resolver 逻辑
即使写了 resolver,若 upstream 定义里用了域名(比如 upstream backend { server api.example.com; }),这部分仍走静态解析,和 proxy_pass 变量无关。
- 动态解析仅适用于
proxy_pass $var;这种写法,upstream块内的域名不会受resolver影响 - 若需基于 upstream 的动态能力,应改用
split_clients+ 变量,或配合 Lua(如 lua-resty-dns)实现 - 临时验证:把
proxy_pass改成 IP(如proxy_pass http://10.0.1.100;),看问题是否消失 —— 若消失,基本锁定是 DNS 解析问题
抓包与日志交叉定位真实目标 IP
Nginx 日志默认不记转发目标地址,需手动增强观测能力。
- 在
log_format中加入$upstream_addr,它会记录实际连接的后端地址(含 IP:port) - 用
tcpdump -i any host -w debug.pcap抓包,确认流量是否真发到了预期新 IP - 检查系统 DNS 缓存(如 systemd-resolved、nscd)是否干扰了 Nginx 自身解析 —— 可临时停用测试
- 修改域名 DNS 后,用
nginx -s reload不会重载 resolver 缓存;只有nginx -s reload+resolver配合valid才能渐进更新











