DNS 解析出问题时,试试我的这套排查方法
半夜被叫起来处理故障,十有八九跟 DNS 有关。用户说网站打不开,你一查发现域名解析不出来;邮件收不到,一查发现 DNS 配置被人改过;新上线的系统别人访问不了,查了一圈是 DNS 缓存没清。这种事儿干这行的都遇到过,今天把我在生产环境里摸爬滚打总结出来的一套排查方法分享出来,Windows、Linux、Mac 三个系统怎么操作,nslookup、dig、traceroute 这些工具怎么用,全都讲清楚。
网络到底通不通,先拿 IP 试一把
很多人一看到网站打不开,第一反应就是敲 nslookup,其实不用这么急。DNS 的活儿是把域名翻译成 IP,如果网络本身就不通,DNS 翻译得再准确也没用。
我的习惯是直接 ping 一个 IP 地址。ping 8.8.8.8,这是 Google 的公共 DNS,国内外基本都能通。或者 ping 114.114.114.114,国内 114DNS 的 IP。如果连这个都 ping 不通,问题在网络层,网线松了、WiFi 断了、网关挂了、出口防火墙拦了,一层层往上查去吧。
反过来,IP 能 ping 通,但 ping www.baidu.com 不通,那才能确定是 DNS 的问题。
Windows 直接 ping 8.8.8.8 就完事,默认四个包自动停。Linux 和 Mac 得加 -c 4,不然后面一直 ping 下去,ping -c 4 8.8.8.8。这一步不花时间,但能帮你省掉很多瞎忙活。
一个域名不行还是所有都不行,先分清楚
确认了是 DNS 的问题,接下来得判断是"全局瘫"还是"局部罢工"。百度能打开但公司内网系统进不去,跟所有网站都打不开,这是两码事。
所有域名都不行的话,大概率是本机配的 DNS 服务器本身挂了,或者到 DNS 服务器的网络链路断了。你可以 ping 一下本机配置的 DNS 地址,看看能不能通。比如你配的是 8.8.8.8,就 ping -c 2 8.8.8.8 试一下。
就一个域名不行的话,可能是这个域名自己的问题,权威 DNS 配置错了、域名过期被暂停了、TTL 没生效导致缓存不一致。
这时候我喜欢用全球 ping 工具查一下各地解析情况。推荐三个我用着顺手的:
ping.pe 界面简洁,全球节点覆盖全,输入域名就能看到每个节点的解析结果和响应时间。有一次我处理一个海外客户的工单,说域名在国内访问慢,打开 ping.pe 一看,欧美节点正常,亚洲几个节点解析出来的 IP 居然是旧的。一问才知道他们刚换了 DNS 服务商,但 TTL 设的是 86400,一天才过期,全球递归服务器还在用老记录。这种情况本地改 DNS 没用,只能等旧缓存过期,或者在权威端把 TTL 调小点。
ping.cn 国内节点比较多,延迟数据更真实。
host-tracker.com 老牌工具,也能看历史记录。
说到 TTL,这玩意儿在生产环境里必须重视。想改域名解析记录的话,提前把 TTL 调小,比如改成 300 秒,等旧的 TTL 时间过了再改记录,改完确认没问题再调回去。不然你这边改完了,全球还有一堆递归服务器拿着旧数据,用户那边持续访问异常,短的持续一两个小时,长的能拖一两天。
本机 DNS 配的啥,得先看清楚
排查方向定了,就该看看本机具体用的哪个 DNS 服务器了。
Windows 下打开命令行,输入 ipconfig /all,往下翻找到"DNS 服务器"那一行。如果显示 192.168.1.1 这种内网地址,说明 DNS 是路由器自动分配的;如果是 8.8.8.8、1.1.1.1 这种,就是手动改过的。企业内网有时候需要配特定的 DNS 服务器,比如公司域控的 IP,配错了内网域名全解析不了。临时改 DNS 的路径是:控制面板 → 网络和共享中心 → 更改适配器设置 → 右键网卡 → 属性 → IPv4 → 手动填 DNS。改完记得执行 ipconfig /flushdns 清缓存,不然可能还在用旧的解析结果。
Linux 下配置文件位置看发行版。老系统直接看 /etc/resolv.conf,但很多新系统这个文件是个软链接,改了重启就没用。CentOS 7 以上用 nmcli dev show | grep DNS,Ubuntu 18 以上用 systemd-resolve --status。Mac 下 scutil --dns 能看到完整配置,或者系统偏好设置里图形界面操作也行。
Mac 有个 mDNSResponder 服务,系统升级之后有时候会抽风,解析 .local 域名慢得要死,等好几秒才有反应。之前有台 Mac 升级到 Big Sur 之后这问题特别明显,重启一下服务就正常了:sudo killall -HUP mDNSResponder。
nslookup 是入门工具,三大系统都能用
这是最基础的 DNS 查询工具,Windows、Linux、Mac 都自带,不用装什么包,上来就能用。
nslookup www.baidu.com默认用系统配置的 DNS 服务器查,返回结果里有几个关键信息:Server 显示实际用的 DNS 地址,Address 是解析出来的 IP,Non-authoritative answer 表示这个结果是从缓存里拿的,不是权威服务器直接给的。
想指定 DNS 服务器查,加上参数就行:
nslookup www.baidu.com 8.8.8.8
nslookup www.baidu.com 1.1.1.1同一个域名用不同 DNS 查出来的结果如果不一样,就有意思了。正常情况下应该是相同的,但如果你配的是运营商 DNS,可能被劫持了,返回的 IP 是广告或者乱七八糟的东西。8.8.8.8 和 114.114.114.114 结果一致但和本地 DNS 不一致,基本就是劫持没跑。
查不同记录类型也方便:
nslookup -type=mx baidu.com :: 邮件记录
nslookup -type=ns baidu.com :: 权威DNS
nslookup -type=txt baidu.com :: SPF/DKIM验证用返回 NXDOMAIN 说明域名不存在,SERVFAIL 说明服务器出问题了,可能是 DNSSEC 配置错误或者权威服务器挂了。
dig 信息更全,查问题用它
dig 在 Linux 和 Mac 上自带,Windows 得装 BIND 或者用 WSL。功能比 nslookup 强大很多,输出信息也详细得多。
dig www.baidu.com输出分好几段。QUESTION SECTION 是你查询的问题,ANSWER SECTION 是返回的答案,包括 A 记录、CNAME 链、TTL,SERVER 是实际查询的 DNS,Query time 是查询耗时。这个 Query time 容易被忽略,如果每次查询都要几百毫秒甚至超时,说明 DNS 服务器响应慢或者网络有问题。
指定 DNS 服务器:
dig @8.8.8.8 www.baidu.com
dig @114.114.114.114 www.baidu.com查各类记录:
dig www.baidu.com A :: A记录
dig baidu.com MX :: 邮件记录
dig baidu.com NS :: 权威DNS
dig baidu.com TXT :: TXT记录
dig -x 8.8.8.8 :: 反向解析PTR只要 IP 地址的话:
dig +short www.baidu.com这一行命令在脚本里用特别方便,不用解析一堆文本。
dig +trace 是我排查 DNS 问题最常用的命令:
dig +trace www.baidu.com它从根服务器开始一级一级往下查,能看到完整的递归过程:先问根服务器拿到 .com 的权威列表,再问 .com 的权威拿到 baidu.com 的权威,最后拿到具体 IP。如果哪一环卡住了或者返回错误,一眼就能看出来。
之前有个项目域名突然解析失败,+trace 走到 .com 权威就停了,返回 SERVFAIL。查了半天发现是域名快过期了,注册商给暂停了解析。赶紧联系注册商续费才恢复。这种问题不 +trace 根本定位不到。
dig 还能看 DNSSEC 验证结果:
dig +dnssec www.baidu.com返回结果里如果有 RRSIG 记录,说明 DNSSEC 配置正常。如果 DNSSEC 验证失败,dig 会返回 SERVFAIL 并且带 validation disabled 或者 Bogus 字样。
Windows 上没 dig 的话,PowerShell 有个替代品:
Resolve-DnsName www.baidu.com
Resolve-DnsName -Type MX baidu.com
Resolve-DnsName -Server 8.8.8.8 www.baidu.com功能差不多,输出格式是 PowerShell 对象,方便脚本处理。
traceroute 看网络路径,定位路由问题
DNS 解析正常但访问慢或者不通,就得看看数据包走的是什么路了。
Windows 用 tracert:
tracert www.baidu.com
tracert -d www.baidu.com加 -d 不解析主机名,纯显示 IP,看着快而且清楚。Windows 的 tracert 默认用 ICMP,有些运营商或者防火墙会限速 ICMP 包,看到全是星号不代表真断了,别被吓到。
Linux 和 Mac 用 traceroute:
traceroute www.baidu.comLinux 下我更推荐装个 mtr,yum install mtr 或者 apt install mtr。这个工具结合了 ping 和 traceroute 的功能,能持续监控每一跳的丢包率和延迟:
mtr -r -c 100 www.baidu.com-r 是报告模式,-c 100 发 100 个包。输出重点看丢包率和延迟突变的那一跳,基本就是问题所在。
之前处理过一个跨境业务慢的问题,mtr 一查发现从国内出去到新加坡那段丢包率 30%,延迟从 50ms 跳到 400ms。反馈给运营商,他们调整了路由策略才解决。
hosts 文件和防火墙,两个容易被忽略的坑
hosts 文件
Windows:C:\Windows\System32\drivers\etc\hosts
Linux/Mac:/etc/hosts
这个文件优先级比 DNS 查询高,系统会先查 hosts 再查 DNS。测试环境经常改 hosts 做验证,改完忘了删或者不小心推到生产环境里,就容易出幺蛾子。
我见过最离谱的一次,有个同事把测试环境的 hosts 映射同步到生产了,导致一个核心域名指向了测试服务器。那天所有用户都打不开正式系统,查了半天最后才想起来看 hosts 文件。
改完 hosts 记得清 DNS 缓存:
- Windows:
ipconfig /flushdns - Linux(nscd):
service nscd restart - Linux(systemd-resolved):
systemd-resolve --flush-caches - Mac:
sudo killall -HUP mDNSResponder
防火墙
DNS 默认走 UDP 53,响应大了会切到 TCP 53。如果防火墙只放行了 UDP 53 但没放 TCP 53,大响应就失败,表现就是有些域名能解析有些不行,特别容易迷惑人。
Linux 看 iptables 规则:
iptables -L -n | grep 53Linux 看 firewalld:
firewall-cmd --list-allWindows 看防火墙:
netsh advfirewall show allprofiles云主机还得看安全组规则。阿里云、腾讯云、AWS 的安全组默认可能没开放 53 端口,自己搭 DNS 服务器的话记得加规则。
DNS 缓存是个多层嵌套的坑
浏览器有缓存,系统有缓存,JVM 有缓存,应用层也有缓存,改完 DNS 记录发现没生效,先别急着骂娘,看看是不是哪层缓存还在用旧的。
浏览器缓存:Chrome 地址栏输入 chrome://net-internals/#dns,能看到缓存记录,点 Clear host cache 就能清。无痕模式可以跳过浏览器缓存,是个简单直接的验证方法。
系统缓存:前面说过了,不重复。
JVM 缓存:Java 应用会缓存 DNS 解析结果。networkaddress.cache.ttl 参数控制缓存时间,JDK 1.8 以后默认 30 秒,但老版本默认是 -1,永久缓存。域名换了 IP,Java 应用不重启就永远连不上新服务器。有个同事换服务器 IP 之后所有服务都正常,就一个 Java 微服务连不上,最后查出来就是 JVM 缓存的问题。
Nginx 缓存:Nginx 启动时解析一次 upstream 域名,之后不会自动更新。upstream 的 IP 变了,Nginx 还连旧 IP。解决方案是用 resolver 指令配合变量,让 Nginx 每次请求动态解析。
抓包是最后的底牌
前面所有方法都试过了还是搞不定,那就 tcpdump 抓包吧,这是最后的手段。
Linux/Mac 抓 DNS 包:
sudo tcpdump -i any -n port 53实时显示所有 DNS 请求和响应。想保存下来分析:
sudo tcpdump -i eth0 -n -s 0 port 53 -w dns.pcap用 Wireshark 打开 dns.pcap,过滤 dns 就能看到所有 DNS 包,dns.flags.response == 0 只看请求,dns.flags.response == 1 只看响应。
有一次我遇到 DNS 查询间歇性超时,dig 查十次能有两三次失败。抓包一看,出去的 UDP 包确实发出去了,但回来的响应包时有时无。查了半天发现是出方向做了 SNAT,状态跟踪表偶尔没记录,回包被丢了。改成不 SNAT 或者强制用 TCP 53 就好了。这种问题不抓包根本定位不到。
实战案例分享
案例一:DNS 劫持
客服说南方某省用户访问我们网站会跳到赌博网站。赶紧 dig @8.8.8.8 和 dig @114.114.114.114 对比,Google DNS 返回正常 IP,114 返回的是赌博网站 IP。确认是运营商 DNS 劫持。解决办法:引导用户换公共 DNS、投诉工信部、给网站加 HTTPS 让劫持后的页面无法正常显示。
案例二:DNSSEC 配置错误
有个客户新上了 DNSSEC,结果全球一半用户访问不了。dig 一查返回 SERVFAIL,dig +dnssec 也没 RRSIG 记录。查出来是 DNSSEC 签名过期了没续签,验证方直接拒绝解析。联系域名注册商续签签名,等全球传播之后就正常了。
案例三:TTL 设置太长
客户换 DNS 服务商,旧记录删了才发现很多节点还在用旧 DNS。TTL 设的 86400,要一天才过期。用户那边断服一整天。正确做法是提前把 TTL 调成 300 秒,等旧 TTL 时间过了再切换,出了问题还能切回来。
案例四:内网 DNS 没配视图
公司内网有个 oa.xxx.com,公网也有这个域名,但解析应该指向内网 IP。结果内网用户解析到公网 IP 了,根本打不开。查了一圈发现 DNS 服务器没配 split-horizon 视图,内网查询和公网查询返回了同样的结果。
总结
DNS 排查其实就那么几条路:先确认网络通不通,再看是单个域名还是所有域名,查本机 DNS 配置,用 nslookup 和 dig 诊断,看缓存和 hosts 文件有没有问题,检查防火墙规则,最后抓包定界。大多数问题几分钟就能定位。
生产环境有几个建议:DNS 服务器一定要有备用的,不要只配一个;重要域名做好监控,IP 变了要告警;改 DNS 之前先调小 TTL;不要在 hosts 里留临时配置超过一天。
遇到 DNS 问题别慌,按这套流程一步步查,基本都能搞定。实在搞不定的,重启一下试试——有时候物理重启能解决百分之九十的玄学问题。
如果觉得这篇内容有帮助,欢迎关注我的公众号耕云躬行录,我会在上面分享更多生产环境的实战经验,都是干货,不整虚的。也可以来我的个人博客 躬行笔记 逛逛,上面有更多排障脚本和工具合集,说不定哪天就用上了。