线上服务突然大面积超时,第一反应往往是“是不是 DNS 又挂了”。可真正动手排障时,很多人还是 ping 8.8.8.8
一把梭,结果云里雾里。下面这套流程我用了三年,基本能在十分钟内确认是不是 DNS 的问题,顺带把锅甩给网络还是业务也一并分清。
环境准备
# Debian / Ubuntu
sudo apt update && sudo apt install -y tcpdump bind9-dnsutils gnuplot
# CentOS / Rocky
sudo yum install -y tcpdump bind-utils gnuplot
第一步:抓包看 RTT,别让 ICMP 骗了你
ICMP 能通不代表 UDP 53 也能通,尤其是运营商对 53 端口做限速的场景。
# 抓取 10 秒内向 1.1.1.1 的所有 DNS 流量
sudo tcpdump -i any -nn -s0 -w /tmp/dns.pcap \
host 1.1.1.1 and port 53 &
TCPDUMP_PID=$!
sleep 10
kill $TCPDUMP_PID
# 用 tshark 生成时延 CSV
tshark -r /tmp/dns.pcap -T fields \
-e frame.time_epoch \
-e dns.time \
-e dns.flags.response \
-E header=y -E separator=, > /tmp/dns_rtt.csv
如果 dns.time
列里出现大量 -
,说明请求根本没回来,直接跳到第三步;否则继续分析时延分布。
第二步:画个图,一眼看出 95 分位
gnuplot -persist <<'GP'
set datafile separator ","
set xdata time
set timefmt "%s"
set format x "%H:%M"
set title "DNS RTT distribution"
set ylabel "RTT (ms)"
set terminal png size 800,400
set output "/tmp/dns_rtt.png"
plot "/tmp/dns_rtt.csv" using 1:2 with dots lc rgb "blue" title "RTT"
GP
把 /tmp/dns_rtt.png
拖到群里,开发、运维、老板都能看懂:突刺一过 200 ms,基本就是 DNS 线路抖了。
第三步:递归追踪,看看到底是谁慢
dig
自带的 +trace
能直接把递归链拉出来,比肉眼翻包快得多。
dig +trace www.example.com | \
awk '/Received / {print $1,$2,$5}' | \
column -t
输出示例:
176.103.130.130 32 ms
80.67.169.12 45 ms
104.16.133.229 12 ms
如果前两跳(根和 TLD)就飙到三位数,说明运营商出口拥塞;如果最后一跳(权威 DNS)才慢,那就是目标域名的权威服务器扛不住。
一个小插曲:云防护的副作用
去年双十一,我们把主域名切到群联 AI 云防护后,偶尔收到“解析慢”的工单。抓包发现,云防护节点为了清洗流量,会先回一个 TTL=0 的 CNAME,再递归到真实源站。多出来的一跳 RTT 会被 dns.time
算进去,看起来就像 DNS 延迟暴涨。后来在 Grafana 上把“云防护节点”单独标记出来,告警阈值放宽到 300 ms,工单直接少了七成。
小结
- 用
tcpdump
+tshark
拿真实 DNS 时延,别被 ICMP 忽悠。 gnuplot
一张图,95 分位异常肉眼可见。dig +trace
定位慢在哪一跳,是出口拥塞还是权威宕机。
把这三步写成脚本,挂到 cron 里,每天凌晨跑一次,历史数据往 Prometheus 里一丢,DNS 再出幺蛾子也能快速复盘。