核心是确认upstream中域名是否静态解析、resolver+resolve是否启用,以及dns缓存是否过期仍被复用;需检查server是否含域名、http/server块有resolver、upstream server后加resolve,并通过日志、dig和抓包交叉验证解析结果是否更新。

排查 Nginx 轮询策略中因 DNS 解析缓存导致的分流异常,核心在于确认 upstream 中域名是否被静态解析、Nginx 是否复用过期解析结果,以及后端节点实际变更后流量是否仍打到旧地址。
确认 upstream 使用的是域名还是 IP
如果 upstream 直接写死 IP(如 server 10.0.1.10:80;),则完全绕过 DNS,不存在该问题。只有使用域名(如 server api.example.com:80;)且未禁用缓存时才可能出问题。检查配置中所有 upstream 块,确认是否有域名形式的 server 条目。
检查 resolver 和 resolve 指令是否启用动态解析
Nginx 默认在启动时解析一次域名并缓存,后续永不更新——这是造成“分流僵化”的主因。要支持定期刷新,必须显式配置:
- 在
http或server块中声明resolver(如resolver 8.8.8.8 valid=30s;) - 在
upstream的server行加上resolve参数(如server api.example.com:80 resolve;) - 注意:仅加
resolve不加resolver会导致启动失败;valid时间决定了缓存多久重查
验证 DNS 缓存是否生效及当前解析结果
可通过以下方式交叉验证:
- 查 Nginx 缓存:Nginx 不提供直接查看内部 DNS 缓存的接口,但可临时开启
error_log /path/to/log debug;并触发请求,日志中会打印 “DNS resolved … to …” 类似行,观察是否随时间变化 - 查系统层面:运行
dig api.example.com +short或nslookup api.example.com,对比返回 IP 与 Nginx 日志中解析出的是否一致、是否已更新 - 查连接实际去向:用
ss -tnp | grep :80或tcpdump -i any host抓包,确认请求真正发到了哪个后端地址
模拟变更并观察轮询行为是否同步更新
最直接的验证方式是人为变更 DNS 解析结果(如修改本地 /etc/hosts、或在测试环境调整权威 DNS 记录),然后:
- 等待超过
valid=设置的时间(如 30s) - 发送多轮请求(curl 多次),用
$upstream_addr变量记录真实转发地址(需在 log_format 中加入) - 观察日志中 upstream 地址列表是否出现新 IP、旧 IP 是否逐渐退出轮询池
不复杂但容易忽略:很多团队只改了 DNS,却忘了 Nginx 需要主动配置 resolver + resolve 才能感知变更。默认行为就是“启动时解析一次,用到进程重启”。











