核心是确认nginx是否使用过期ip:日志中upstream后显示的ip若与dig结果不一致,即为dns缓存问题;proxy_pass直写域名会静态缓存,需改用变量+resolver或重载nginx刷新。

排查 Nginx 代理后端服务时的 DNS 解析缓存问题,核心在于确认“Nginx 是否用了过期 IP”,而不是单纯看系统能否解析域名。它常表现为:后端 DNS 已更新、本地 curl 或 nslookup 能查到新 IP,但 Nginx 仍连老地址并报 Connection timed out 或 upstream prematurely closed connection。
看 error.log 里实际连的是哪个 IP
这是最直接的线索。Nginx 不会写“DNS 缓存过期”,而是把缓存的 IP 写进日志:
- 搜索
upstream timed out或connect() failed,重点看upstream:后面的地址,例如:upstream: "http://10.20.30.40:80/"—— 这个 IP 就是 Nginx 当前缓存并正在用的 - 对比这个 IP 和你当前用
dig your-domain.com +short查到的结果是否一致。不一致,基本就是 DNS 缓存问题 - 注意:
proxy_pass http://backend.example.com这种写法,Nginx 只在首次请求时解析一次,之后长期缓存(可能数天),不会随系统 DNS 变更自动刷新
验证 resolver 配置是否生效且作用域正确
想让 Nginx 运行时动态解析,必须显式配置 resolver,且它只对变量形式的 proxy_pass 生效:
- 检查配置中是否有
resolver指令,并确认它写在location或server块内(不是只放在http块顶层) - 确保
proxy_pass用了变量,例如:set $upstream "api.example.com";<br>proxy_pass https://$upstream;
如果直接写proxy_pass https://api.example.com;,resolver完全不起作用 - 验证 DNS 服务器本身是否可达:在 Nginx 所在机器上执行
nslookup api.example.com 8.8.8.8,确认能返回预期 IP
区分 upstream 域名与 proxy_pass 变量的缓存机制
两种写法行为完全不同,排查方向也不同:
-
upstream 块里写域名(如
upstream backend { server api.example.com; }):
— Nginx 启动/重载时解析一次,之后完全静态,不支持resolver,也不支持 TTL 刷新
— 解决方案只有重载 Nginx 或改用第三方模块(如nginx-upstream-dynamic-servers) -
proxy_pass 使用变量 + resolver:
— 每次请求都可能触发解析,缓存时间由valid=60s控制
— 注意:valid是缓存有效期,不是强制刷新间隔;若 DNS 返回 TTL=300,Nginx 会取两者最小值
临时绕过问题并确认根因
快速验证是不是 DNS 缓存导致,可用最简方式隔离:
- 在 Nginx 机器的
/etc/hosts中临时加一条:1.2.3.4 api.example.com(填当前正确的 IP)
然后nginx -s reload,观察是否立即恢复 —— 如果恢复,说明确实是 DNS 解析环节的问题 - 或者直接把
proxy_pass改成 IP:proxy_pass http://1.2.3.4:8080;,同样 reload 测试
若正常,基本排除网络、防火墙、后端服务本身问题,聚焦 DNS 缓存 - 容器环境额外检查:
cat /etc/resolv.conf看 nameserver 是否指向 kube-dns/coredns;短域名(如redis)需补全为redis.default.svc.cluster.local











