DNS 是那种"平时完全想不起来、一出问题就全线瘫痪"的基础设施。它的故障表现也很有迷惑性:ping: unknown host 看着像网络断了,但 IP 直连一切正常;网站打不开,但服务器资源、端口、防火墙全都没问题;更麻烦的是"部分地区能访问、部分地区不行",因为不同运营商的递归 DNS 缓存了不同的结果。
这篇文章先讲清楚一次 DNS 解析到底发生了什么,然后列出常见失败原因和对应的诊断命令,重点是 dig +trace 的正确用法、systemd-resolved 带来的 /etc/resolv.conf 变形问题、以及用 hosts 文件做临时验证的技巧。最后给出预防和监控建议。
一、一次 DNS 查询到底走了哪几步
理解流程,才能判断问题出在哪一步。
应用(浏览器/curl)
→ 应用自身缓存(部分应用有,如 Java JVM)
→ 操作系统缓存 + /etc/hosts
→ stub resolver(本机解析器,如 systemd-resolved 的 127.0.0.53)
→ 递归 DNS 服务器(运营商 DNS 或你配置的公共 DNS)
→ 根服务器(.)
→ 顶级域服务器(.com)
→ 权威 DNS 服务器(你的域名解析商)
← 逐级返回,按 TTL 缓存
关键点:
递归服务器替你跑腿。 你的服务器只向递归 DNS 发一个查询,剩下从根到权威的迭代查询由递归服务器完成。
各级都有缓存。 操作系统有缓存、递归服务器按 TTL 缓存、应用自己也可能有缓存。所以改了解析记录不会立刻全网生效。
TTL 决定了生效速度。 记录里设置的 TTL(秒)就是各级缓存的最长保留时间。TTL 600 意味着最坏情况下要等 10 分钟才全网生效。
hosts 文件优先级最高。 在 /etc/nsswitch.conf 里 hosts: 行的顺序决定了优先级,通常是 files dns,即先查 hosts 再查 DNS。
常见的记录类型:
| 类型 | 用途 |
|---|---|
A |
域名到 IPv4 地址 |
AAAA |
域名到 IPv6 地址 |
CNAME |
别名,指向另一个域名 |
MX |
邮件服务器 |
NS |
权威域名服务器 |
TXT |
文本记录(SPF、域名验证等) |
SOA |
起始授权记录,包含序列号、刷新间隔等 |
PTR |
反向解析(IP 到域名) |
二、先看错误类型:不同返回码含义完全不同
用 dig 查询时,输出头部的 status 字段直接说明了失败类型:
dig www.example.com A
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
| status | 含义 | 常见原因 |
|---|---|---|
NOERROR |
查询成功 | 但要看 ANSWER 段是否有记录,为 0 说明记录类型不匹配 |
NXDOMAIN |
域名不存在 | 记录真的没配、主机名拼错、或者权威服务器没有这条记录 |
SERVFAIL |
服务器失败 | 最复杂:DNSSEC 校验失败、权威服务器全部不可达、递归服务器故障 |
REFUSED |
查询被拒绝 | 目标 DNS 服务器不允许你递归(比如拿公共 DNS 当转发器配置错) |
| 无响应/超时 | 网络问题 | UDP 53 被拦、被限速、防火墙问题 |
看 flags 也有用:ra(Recursion Available)表示服务器支持递归查询;aa(Authoritative Answer)表示这是权威应答。查权威服务器时应该有 aa。
dig @ns1.example.com www.example.com A # 直接问权威,看是否有 aa 标志
三、用 dig 逐层定位
基本查询
dig www.example.com A # 完整输出
dig www.example.com A +short # 只要结果
dig www.example.com AAAA +short # IPv6
dig www.example.com ANY +short # 所有记录(部分服务器不支持)
dig -x 1.2.3.4 # 反向解析
输出里的 Query time 反映本次查询耗时,正常应在几十毫秒内。持续超过几百毫秒说明递归 DNS 有问题。
dig +trace:完整追踪解析链
这是排查 DNS 问题最重要的一个命令。它会模拟递归服务器的行为,从根服务器开始一路问下去,把每一级的应答都打印出来:
dig +trace www.example.com
输出大致是这样几段:
. 从根服务器拿到 .com 的 NS 列表
com. 从 .com 服务器拿到 example.com 的 NS 列表
example.com. 从 example.com 的权威服务器拿到 www 的 A 记录
怎么用它判断问题在哪:
| 卡在哪一段 | 说明 |
|---|---|
| 根服务器段就没响应 | 本机网络有问题,或 UDP 53 出网被封 |
能到 .com 但到 example.com 无响应 |
权威 DNS 服务器全部不可达或配置错误 |
| 到了权威服务器但返回 NXDOMAIN | 记录真的不存在,去解析控制台检查 |
全程正常但 dig 不加 +trace 时结果不对 |
递归 DNS 的缓存或劫持问题 |
最后一种情况特别有诊断价值:dig +trace 拿到的是权威的真实答案,直接 dig 拿到的是递归服务器给你的答案。两者不一致时,问题就在递归 DNS 上(缓存、污染、或劫持)。
用多个公共 DNS 对比
这是判断"是不是本地 DNS 有问题"最快的办法:
for dns in 223.5.5.5 119.29.29.29 114.114.114.114 8.8.8.8; do
echo "== $dns =="
dig @$dns www.example.com A +short
dig @$dns www.example.com A | grep -E 'Query time|status:'
done
| 公共 DNS | 地址 |
|---|---|
| 阿里 | 223.5.5.5、223.6.6.6 |
| DNSPod | 119.29.29.29 |
| 114DNS | 114.114.114.114 |
| 8.8.8.8、8.8.4.4 | |
| Cloudflare | 1.1.1.1 |
对比结果的几种情况:
- 所有 DNS 结果一致且正确 → DNS 没问题,查别的
- 所有 DNS 都返回 NXDOMAIN → 记录真的没配,去控制台加
- 只有本地 DNS 结果不同 → 本地 DNS 缓存污染或劫持
- 境外 DNS 正常、境内 DNS 异常 → 可能是域名状态问题(如未实名被暂停)
用 TCP 模式排除 UDP 限速
DNS 默认用 UDP 53,但响应超过 512 字节(启用 DNSSEC 后更容易超过)时会转用 TCP。如果 UDP 53 被限速或丢包,就会出现"时好时坏"的解析失败:
dig +tcp @8.8.8.8 www.example.com A
如果 TCP 模式稳定而 UDP 模式超时,基本可以确定是 UDP 53 被限速或丢包。
其他有用的 dig 用法
dig example.com NS +short # 看权威服务器有几个、是否可达
dig example.com SOA +short # 看序列号,判断是否已更新
dig example.com MX +short # 邮件记录
dig +dnssec www.example.com # 看 DNSSEC 相关记录
dig www.example.com +stats # 只看统计信息
SOA 记录里的序列号很实用:改了记录后,看权威服务器的 SOA 序列号是否增加,就知道变更有没有生效。
四、nslookup 与 Windows 上的工具
nslookup 是另一个常用工具,Windows 上默认自带:
nslookup www.example.com
nslookup www.example.com 223.5.5.5 # 指定 DNS 服务器
nslookup -type=AAAA www.example.com
nslookup -type=NS example.com
nslookup -debug www.example.com # 详细输出
Windows PowerShell 上更现代的选择:
Resolve-DnsName www.example.com
Resolve-DnsName www.example.com -Type AAAA
Resolve-DnsName www.example.com -Server 223.5.5.5
Clear-DnsClientCache # 清本地缓存
Get-DnsClientCache # 看缓存内容
ipconfig /displaydns # 命令行看缓存
ipconfig /flushdns # 清缓存
注意 nslookup 的一个行为特点:它在查询失败时可能返回"不存在的域",即使是超时造成的。判断时要结合多个工具的结果,不要只看 nslookup 一句话。
五、resolv.conf 与 systemd-resolved 的坑
这是 Linux 服务器上最常见的 DNS 配置困惑来源。
/etc/resolv.conf 老是被覆盖
你可能手动改了 /etc/resolv.conf,重启或重启网络后又变回去了。因为有多个程序都在管理它:
- NetworkManager:按连接配置写入
- systemd-resolved:把自己作为 stub 监听在 127.0.0.53
- cloud-init:云服务器初始化时会写
- dhclient / resolvconf:DHCP 客户端会更新
先确认它是不是符号链接:
ls -la /etc/resolv.conf
cat /etc/resolv.conf
如果看到:
nameserver 127.0.0.53
options edns0 trust-ad
search .
说明本机在用 systemd-resolved 做 stub resolver,真正的 DNS 服务器配置不在 resolv.conf 里。
systemd-resolved 的诊断命令
resolvectl status # 查看每个接口的 DNS 配置(新版本)
resolvectl query www.example.com # 用它查询
resolvectl statistics # 统计信息,看缓存命中与失败数
resolvectl flush-caches # 清缓存
# 老版本命令(仍广泛可用)
systemd-resolve --status
systemd-resolve --statistics
systemd-resolve --flush-caches
resolvectl status 的输出里会分别列出 Global(全局 DNS)和每个网卡的 DNS 设置。注意实际生效的是当前网卡的配置,改了 Global 但网卡上有自己的 DNS 时,可能走的是网卡那个。
修改方式:
# NetworkManager 管理时
nmcli con show
nmcli con mod eth0 ipv4.dns "223.5.5.5 119.29.29.29"
nmcli con mod eth0 ipv6.dns "2400:3200::1"
nmcli con up eth0
# 或改 /etc/systemd/resolved.conf 的全局配置
[Resolve]
DNS=223.5.5.5 119.29.29.29
FallbackDNS=8.8.8.8
sudo systemctl restart systemd-resolved
resolvectl status
不推荐的做法是用 chattr +i /etc/resolv.conf 锁住文件。 这会导致网络管理服务报错,且后续排查时更难理解发生了什么。正确做法是去配置真正管理它的那个服务。
Ubuntu 上如果用的是 netplan,DNS 配置写在 yaml 里:
network:
version: 2
ethernets:
eth0:
nameservers:
addresses: [223.5.5.5, 119.29.29.29]
sudo netplan try
sudo netplan apply
用系统解析器验证
getent hosts www.example.com # 走完整的系统解析路径(nsswitch + hosts + DNS)
getent 的结果和 dig 不一致时,说明问题在系统的解析路径上(hosts 文件、nsswitch 顺序、或 stub resolver 配置),而不是 DNS 服务器本身。
六、常见失败原因清单
| 原因 | 典型表现 | 诊断方法 |
|---|---|---|
| 记录写错或没配 | NXDOMAIN | dig +trace、dig @权威 NS |
| 域名未实名/未备案被暂停 | 境内 DNS 解析失败,境外正常或也失败 | whois 查域名状态 |
| 权威 DNS 服务器故障 | +trace 到权威段无响应 |
dig example.com NS 逐个测 |
| TTL 缓存未过期 | 改了记录但部分地区还是旧值 | 查返回的 TTL 值 |
| DNSSEC 校验失败 | SERVFAIL | dig +dnssec、查 DS 记录 |
| 本地 DNS 污染/劫持 | 返回错误 IP | 多 DNS 对比、+trace 对比 |
| resolv.conf 被覆盖 | 改了配置重启又回去 | ls -la /etc/resolv.conf |
| systemd-resolved 配置错 | 部分接口不通 | resolvectl status |
| 防火墙拦 53 | 解析超时 | tcpdump port 53 |
| UDP 53 限速/丢包 | 时好时坏 | dig +tcp 对比 |
| 应用自带缓存 | 系统解析正常但应用失败 | 重启应用、清应用缓存 |
域名状态被暂停
这是国内域名特有的问题,且不常被想到。域名如果未完成实名认证、或涉及备案问题,注册局会设置 clientHold 或 serverHold 状态,该域名会被全局停止解析。
whois example.com | grep -i -E 'status|hold'
正常状态应包含 ok 或 clientTransferProhibited 这类正常标记;出现 clientHold、serverHold 就说明被暂停了。解决方式是去注册商处完成实名认证或处理违规,处理完成后状态恢复,解析才会恢复。
DNSSEC 问题
DNSSEC 通过数字签名保证解析结果未被篡改,但配置错误会导致整条链校验失败,表现为 SERVFAIL。
dig +dnssec www.example.com
dig example.com DS +short # 看上级是否发布了 DS 记录
常见的失败场景:换了域名解析服务商,但注册商处还留着旧服务商的 DS 记录;或者解析商开了 DNSSEC 但注册商没同步 DS。结果是签名链断裂。
处理:要么在注册商处更新或删除 DS 记录,要么先在解析商处关闭 DNSSEC 恢复服务,再慢慢修正。
风险提示:操作 DNSSEC 记录有导致域名完全不可解析的风险,且不熟悉时容易改错。建议先在测试域名上验证,或者联系解析服务商的技术支持协助。修改前记录当前 DS 记录的完整内容以便回滚。
防火墙与 53 端口
sudo tcpdump -i eth0 -nn 'port 53'
sudo iptables -L -n -v | grep -E '53|domain'
要同时放行 UDP 53 和 TCP 53。 很多人只放了 UDP,导致大响应(超过 512 字节,启用 DNSSEC 后很常见)无法回落 TCP,表现为"大部分域名能解析,某些域名不行"。
云安全组也要检查出方向的 UDP/TCP 53。
七、用 hosts 文件做临时验证
当你怀疑是 DNS 问题、需要快速恢复业务时,hosts 文件是最直接的临时方案。
Linux:
sudo vi /etc/hosts
# 添加一行
1.2.3.4 www.example.com
getent hosts www.example.com # 验证是否生效
Windows(需要管理员权限编辑):
C:\Windows\System32\drivers\etc\hosts
添加同样格式的一行,然后执行 ipconfig /flushdns 清缓存。
hosts 的几个注意点:
- 这是临时方案,只在本机生效,其他机器和用户仍然解析失败
- 加之前先用
dig +trace或dig @公共DNS确认正确的 IP,不要凭记忆填 - 问题修好后一定要删掉,否则将来 IP 变更时会出现"其他人都正常、就这台机器连到旧 IP"的诡异故障
- 服务器数量多时,改 hosts 不现实,应该修 DNS 本身
八、解决与预防
排查顺序建议
# 1. 确认本地解析结果
getent hosts www.example.com
dig www.example.com A +short
# 2. 换个公共 DNS 对比
dig @223.5.5.5 www.example.com A +short
dig @119.29.29.29 www.example.com A +short
dig @8.8.8.8 www.example.com A +short
# 3. 追踪完整解析链
dig +trace www.example.com
# 4. 直接问权威服务器
dig @权威NS www.example.com A
# 5. 检查域名状态
whois example.com | grep -i status
# 6. 检查本机解析器
resolvectl status
cat /etc/resolv.conf
# 7. 抓包确认 53 端口
sudo tcpdump -i eth0 -nn 'port 53'
预防措施
配置两个以上的 DNS 服务器。 主用 223.5.5.5,备用 119.29.29.29 或 8.8.8.8。单一 DNS 故障是常见事故。
变更解析前先把 TTL 调小。 提前一天把 TTL 改成 300 或 600,变更时就能快速生效,改完再调回大值减少查询压力。这是做迁移和切换的标准动作。
监控解析结果。 从多个地区、多个运营商定期解析关键域名,比对结果是否与预期一致。这能在用户投诉前发现污染或配置错误。
关键服务考虑 IP 直连或保留备用域名。 对一些关键的内部依赖,可以在配置里保留 IP 兜底,或者准备一个不同后缀的备用域名。
记录权威 NS 清单并定期检查可达性。 用 dig example.com NS +short 拿到所有权威服务器,逐个测试它们是否都能正常应答。部分 NS 不可达时平时没感觉,一旦其他 NS 故障就会放大问题。
不要过度依赖 /etc/hosts 做长期方案。 它会掩盖问题,且在多台机器间难以同步。
常见问题
改了解析记录多久生效?
取决于原记录的 TTL。如果 TTL 是 3600 秒,最坏情况要一小时各级缓存才过期。各地运营商的递归服务器刷新节奏不同,所以会表现为"部分地区已生效、部分地区还是旧的"。下次变更记得提前把 TTL 调小。
为什么境外 DNS 能解析、境内不行?
几种可能:域名被设置了 hold 状态(未实名或未备案);境内递归 DNS 缓存了旧结果;或者域名解析服务商在境内没有节点导致响应慢。先用 whois 查域名状态,再用 dig +trace 看权威段的应答。
ping 提示 unknown host,但 IP 能 ping 通,是什么问题?
典型的 DNS 问题,网络层正常。按排查顺序走:dig 看返回码、换公共 DNS 对比、dig +trace 追链、检查 /etc/resolv.conf 和 resolvectl status。
systemd-resolved 和 /etc/resolv.conf 到底是什么关系?
systemd-resolved 提供一个本地 stub 解析器(通常监听 127.0.0.53),并把 /etc/resolv.conf 指向它。所以你在 resolv.conf 里只看到 127.0.0.53,真正的上游 DNS 要用 resolvectl status 看。直接改 resolv.conf 会在网络重启后被覆盖。
怎么判断是不是 DNS 被劫持?
对比 dig +trace(权威真实答案)和直接 dig(递归服务器答案)的结果。如果两者 IP 不同,说明递归环节有问题。再换几个公共 DNS 对比,如果只有默认那个返回错误结果,就可以确定是它的问题。
服务器上要不要配 8.8.8.8?
境内服务器不建议把它作为首选。境外 DNS 在境内的响应速度和稳定性都不如境内公共 DNS,且部分情况下会被干扰。建议首选 223.5.5.5 或 119.29.29.29,境外 DNS 作为备用或者排查对比时使用。
清 DNS 缓存有用吗?
有用,但只清本机那一层。systemd-resolved 用 resolvectl flush-caches,Windows 用 ipconfig /flushdns,应用自身的缓存要重启应用。运营商递归服务器的缓存你清不掉,只能等 TTL 过期。
总结
- 理解解析链是排查的基础:应用缓存 → hosts → stub resolver → 递归 DNS → 根 → TLD → 权威。
dig +trace拿到的是权威真实答案,直接dig拿到的是递归服务器的答案,两者不一致就说明问题在递归环节(缓存、污染或劫持)。 - 先看返回码再动手:
NXDOMAIN是记录不存在或写错,SERVFAIL多是 DNSSEC 或权威服务器问题,REFUSED是递归被拒,超时则是网络或 53 端口问题。 - 多 DNS 对比是最快的定位手段:用 223.5.5.5、119.29.29.29、114.114.114.114、8.8.8.8 分别查一遍,一致说明 DNS 正常,只有本地那个不同就是本地 DNS 的问题。
- systemd-resolved 是 Linux 上最大的困惑源:
/etc/resolv.conf里的127.0.0.53只是 stub,真实配置要用resolvectl status看;改配置要改 NetworkManager、netplan 或resolved.conf,不要用chattr +i锁文件。 - 境内域名特有的坑是状态被暂停(
clientHold/serverHold,多因未实名或未备案),用whois 域名 | grep -i status检查;DNSSEC 配置错误会表现为SERVFAIL,紧急处理是先在解析商处关闭再慢慢修正,改前务必记录原 DS 内容。 - 防火墙要同时放行 UDP 53 和 TCP 53,只放 UDP 会导致大响应无法回落,表现为"部分域名解析不了";怀疑 UDP 被限速时用
dig +tcp对比验证。 - hosts 文件只作为临时止血手段,用完必须删除;长期预防靠多 DNS 冗余、变更前提早调小 TTL、以及从多地定期监控解析结果。
企业QQ咨询




