Nginx proxy_pass 使用变量时,DNS 缓存只认 resolver 的 valid 值而非上游 DNS TTL;valid 是 Nginx 内存缓存的强制保质期,决定解析刷新节奏,且 resolver 必须与变量同配置层级才生效。

proxy_pass 用变量时,DNS 缓存过期时间不看上游 DNS 的 TTL,只认你配置的 valid 值。 这是绝大多数人调不通动态解析的根本原因——误以为改了权威 DNS 的 TTL,Nginx 就会自动跟着变。
为什么 valid 参数比 DNS TTL 更关键
Nginx 的 resolver 不是“被动遵循 DNS TTL”,而是“主动按 valid 时间强制刷新缓存”。哪怕你把权威 DNS 的 TTL 设为 1 秒,Nginx 若配了 valid=30s,它就绝不会早于 30 秒去查新 IP;反过来,若权威 TTL 是 3600 秒,但你设了 valid=5s,Nginx 仍每 5 秒就重查一次。
-
valid是 Nginx 自己的缓存保质期,和 DNS 协议层的 TTL 无直接继承关系 - resolver 查到的记录(A/AAAA)会被 Nginx 存进内存缓存,
valid控制这个内存缓存的失效时间 - 只有缓存真正过期后,下一次需要建连(比如连接池里没可用连接、或连接被标记为失效),才会触发新解析
- 日志中出现
resolving ... timed out或could not be resolved,往往说明valid太短 + DNS 服务器响应慢,导致反复失败 fallback
proxy_pass 变量写法必须严格匹配 resolver 作用域
resolver 必须和变量出现在同一配置块层级,否则 Nginx 根本不调用它。常见失效场景:
- 在
http块顶层写了resolver 1.1.1.1 valid=10s;,但在location里用set $upstream "api.example.com"; proxy_pass http://$upstream;—— 旧版 Nginx( - resolver 写在
server块,但变量在嵌套的location里定义,而该 location 没有显式继承 resolver(1.19.9+ 支持继承,但低版本不行) - 用了
upstream块:无论是否带域名,upstream server example.com:80;始终静态解析,resolve参数仅在 1.19.9+ 的upstream中有效,且需显式声明
如何验证 valid 是否真正生效
不能只看配置有没有语法错误,得观察运行时行为:
- 开启
error_log /var/log/nginx/error.log debug;,搜索resolving关键字,确认是否在valid间隔后重复出现 - 临时修改本地
/etc/hosts,让域名指向一个 unreachable 的 IP,然后等valid时间过后,检查 error log 是否出现新一次resolving并最终失败 - 用
strace -p $(pgrep nginx) -e trace=connect抓 worker 进程的connect()系统调用,看目标 IP 是否在valid后变化(注意:只对首次建连有效,复用 keepalive 连接时不会重解析) - 避免用
nginx -T看结果——它只显示启动时解析的 IP,不是运行时缓存值
最易被忽略的一点:valid 控制的是“缓存生命周期”,不是“每次请求都查 DNS”。Nginx 仍会复用已建立的连接,除非连接断开或被标记为不可用。所以即使 valid=5s,你也可能连续几十秒都发往同一个 IP——这不表示失效,而是连接池在起作用。











