Nginx轮询因DNS缓存导致分发异常,核心是验证IP是否真实更新及Nginx是否使用新IP转发;需满足Nginx≥1.19.9、http块配resolver及valid、upstream中server后加resolve三条件,否则仍为静态解析。

排查 Nginx 轮询负载均衡因 DNS 缓存导致的分发异常,核心不是看“轮询是否均匀”,而是确认后端 IP 是否真实更新、Nginx 是否真的在用新 IP 转发请求。DNS 缓存不刷新,轮询就只是在旧 IP 列表里打转——哪怕你改了权威 DNS 记录,Nginx 仍可能持续往已下线的机器发流量。
确认 Nginx 是否启用动态 DNS 解析
静态配置域名(如 server api.example.com;)在启动时只解析一次,后续 IP 变更完全无效。要支持运行时更新,必须同时满足三个条件:
- Nginx 版本 ≥ 1.19.9(低版本不支持
resolve参数) -
http块中存在有效的resolver指令,例如:resolver 8.8.8.8 valid=10s;(不能写成127.0.0.1且本地无 DNS 服务) -
upstream中的server行末尾明确带resolve,例如:server api.example.com resolve;(缺这个词就等于没开动态解析)
验证 DNS 缓存是否实际更新
别依赖 curl 或业务日志判断,要抓 Nginx 内部行为:
- 执行
nginx -s reload不会清空 DNS 缓存;只有等待valid时间到期,或重启 Nginx 才会强制重查 - 查错误日志:
tail -f /var/log/nginx/error.log,重点找resolver timeout、failed to resolve、no address等关键词 - 手动模拟解析:
dig api.example.com @8.8.8.8 +short,再对比 Nginx 当前建连目标(用ss -tnp | grep :80或 tcpdump 抓包看 real upstream IP)
检查流量是否落到新 IP 上
即使 DNS 解析成功,Nginx 默认也不会主动淘汰失效后端——它只靠 max_fails + fail_timeout 触发临时规避,不会从 DNS 缓存里删地址:
- 务必在
server行中配置健康探测参数,例如:server api.example.com resolve max_fails=2 fail_timeout=15s; -
proxy_next_upstream需配合设置(如error timeout http_502),才能在失败后尝试下一个 upstream 成员 - 若需实时观察当前解析结果,原生 Nginx 无命令行查缓存能力,只能靠日志 + 外部
dig交叉比对
排除系统级 DNS 干扰
某些环境会让 Nginx 的 resolver 表现异常,尤其容器和精简镜像:
- K8s Pod 中检查
/etc/resolv.conf:nameserver 是否指向 coredns?search 域是否补全(如短域名redis应写成redis.default.svc.cluster.local) - Alpine 镜像默认用 musl libc,不支持 EDNS0,内网 DNS 可能拒绝响应;可临时换 Ubuntu 镜像或加
--dns=8.8.8.8启动验证 - 避免在
location或server块里重复写resolver—— 它只在http块生效,其他位置无效


















