DNS监控与故障排查实战:从解析链路到预警方案
发布时间:2026/10/21 15:45:49 锦皓数字建站

在线上业务的日常运维里DNS往往是最容易被当成“小事”的那一环。域名解析成功就像空气一样平时没人会认真盯着它等它一旦出问题整套业务就会被放倒。前些时候某大型社交平台出现大规模访问异常很多人第一反应是服务器扛不住或者网络断了但把链路拉出来复盘才发现问题的根子恰恰出在DNS解析上。那次故障期间用户端看到的是页面转圈、App连不上运维后台的CPU、带宽、内存却全都健康可用户就是打不开——这种“看起来什么都没有坏但所有人都进不来”的状态最考验人也最能说明DNS监控缺失的代价。这篇文章不是讲某一次具体故障的八卦而是想把“如何及时发现DNS问题”这件事拆开揉碎先聊DNS为什么有这么大的破坏力再总结故障的常见形态然后给出我实际在用的监控方案、排查链路以及事前演练方法。适合SRE、运维工程师、后端开发以及自己维护独立站的人在遇到类似问题时参考。看完至少能回答三个问题该盯哪些指标、怎么从解析结果判断故障位置、以及在业务被DNS放倒之前我们能准备点什么。1. 大平台宕机背后的底层逻辑DNS为什么有这么大破坏力1.1 一次访问背后要过好几道解析关卡每一道都是断点很多人觉得DNS不就是“把域名变成IP”吗能有多复杂。说句实在话单独看某一步确实简单但整条链路串起来之后它就是一套层层依赖的分布式系统。用户在浏览器里敲一个域名浏览器先看自己的缓存没有就找操作系统的解析器配置操作系统再把它交给配置好的递归DNS服务器。这个递归服务器如果也没缓存就要替用户往上查先找根服务器再找顶级域名服务器最后找到负责这个域名的权威服务器拿到真实的解析记录再原路返回给用户。如果业务还接了CDN或者做了按地域分流的智能解析那权威服务器返回的IP可能因为用户位置不同而不同它在承担解析工作的同时也在做流量调度。这里每一层节点都有可能出现故障也都可能成为恢复的瓶颈。我把这条链路类比成“打电话要先查电话簿”DNS就是电话簿。服务器本身没问题相当于人站在电话旁好好等着DNS出问题等于电话簿被人撕了一半或者打电话的人拿到了一个错误的号码。用户只知道自己“打不通电话”绝不会第一时间想到是电话簿出了问题。1.2 故障期间看起来一切正常这正是DNS问题的阴险之处我经历过不少类似场景监控大屏上所有业务指标都是绿的服务进程没挂带宽没打满数据库延迟也正常但客服那边已经连续收到几十个“网站打不开”的反馈。一开始我们往往怀疑是最近一次上线引入的Bug或者网络出口被封了排查了半天才发现其实问题根本不在业务侧而是某个权威DNS服务器连续几分钟没有正确响应或者递归解析器返回了一堆错误结果。为什么会这么容易误判因为DNS层故障的“症状”和网络故障太像了都是用户访问不了。而绝大多数内部监控系统监控的是业务自身的可用性比如HTTP状态码、进程状态、负载情况它们触发的前提是“请求已经到达业务服务器”。DNS一旦在入口之前拦截了流量请求根本到不了业务层内部监控自然什么也发现不了。等到发现的时候往往已经是用户大面积反馈了那才是真正被动的时候。另外DNS问题还有一个特点影响范围是慢慢扩散、慢慢恢复的因为各级缓存都有TTL生存时间。某个权威节点出了问题不同地区、不同运营商用户感受到的时间点会错开恢复的时候也要等旧缓存逐级过期新的解析结果才会推到位。这不像服务器崩溃重启一下所有人立刻就能访问DNS的恢复天然带着延迟和不确定性。所以监控DNS不能等故障全面爆发之后再做必须提前部署。2. 按故障形态做分类DNS出问题远不止“解析失败”这一种2.1 权威层失效域名托管方、权威服务器或记录配置先挂掉这是最常见的一类。权威DNS服务器是解析链路的“最终答案来源”它挂了或者它上面的记录被人改坏、删掉了全球用户的解析都会乱套。具体表现为使用dig命令直接查询权威服务器时返回超时、REFUSED或者返回空结果。典型场景有两个一是域名托管平台自己的基础设施出问题这种情况我们控制不了只能等着对方恢复或快速切换备用解析服务二是自己维护权威DNS时误操作把NS记录改了或者给某个子域名配错了解析记录。第二个场景我踩过真实的坑某次做机房切换把服务器A解析到新的IP后随手把旧记录删了但忘了还有一个子域名的CNAME指向旧域名结果旧域名删除后子域名也跟着大面积解析失败排查时看着报错一头雾水最后翻变更记录才发现是两个配置之间的隐式依赖。2.2 递归层故障Local DNS缓存了坏结果用户集体遭殃权威服务器是好的业务也完全正常运行但用户依然打不开这种情况多半出在递归解析层。用户的终端不会直接去查权威服务器它只会请求自己配置的递归DNS服务商。一旦这些递归服务商内部出了问题——比如到权威服务器的链路拥塞、错误缓存了SERVFAIL响应、或者在内部更新过程中有缺陷——那么一大片用户都会被带偏。这一类故障有个非常典型的特征你把自己电脑的DNS临时换成另一个公共DNS问题立刻消失但用原本的运营商DNS继续解析还是会失败。这说明不是你的域名或者权威层有问题而是现在这批递归服务商没有正确执行递归解析。遇到这种情况运维能做的事情其实非常有限因为你没法直接操纵用户侧的递归服务商缓存只能通过监控尽早发现然后判断影响范围必要时在业务侧提供一个可用的备用入口方案比如引导用户切换DNS或者临时下发客户端内置IP。2.3 配置与变更风险TTL设太短、通配符失误、割接不同步还有一类故障既不是硬件挂了也不是链路断了纯粹是配置层面的人为问题。我见过最多的是三种TTL设得太短。有些团队为了快速切换IP把TTL设成30秒甚至10秒本意是好的想让变更即时生效。但如果某个解析记录每次查询都有波动或偶尔超时短TTL会把这种波动放大几十倍因为缓存来不及吸收抖动每个用户每次访问都直接打到源站一抖动就失败。通配符误用。比如给主域加了*.example.com的泛解析之后某个API子域名本来应该由另一个CNAME记录控制表面上查的时候都能返回IP但不同子系统用同一个泛解析入口造成的流量倾斜、证书不匹配问题反而更难排查。割接不同步。业务侧已经把所有流量切到了新机房但DNS记录还指向旧机房或者新旧记录交替发布导致同一时间一部分用户访问新IP、一部分用户访问旧IP两边都以为对方出问题了。这种故障最迷惑人因为它表现成“时好时坏”而且不同地域看到的结果还不一样。2.4 一张表快速对照DNS故障形态与发现手段故障层/类型典型表现最快的发现手段恢复动作权威服务器宕机所有递归普遍超时/解析失败直接探测权威服务器切换备用NS/迁移托管权威记录被误删/误改解析结果为空或指向错误IPDNS配置变更审计、解析结果快照对比回滚配置等待TTL过期递归缓存错误部分运营商用户集体打不开换DNS即好多地域、多DNS探测对比联系递归服务商等待或主动刷新DNSSEC签名过期/算法错误全局解析SERVFAIL外部完全不可用DNSSEC验证探针重新签名并发布域名记录被篡改/异常应答解析出来的IP与预期不符解析结果与真实IP自动比对修正记录并排查篡改来源这张表并不是标准答案它更像是排查时的“分类检索”工具。我自己的经验是遇到DNS异常第一件事不是继续查业务日志而是先判断是哪一层的问题。层判断对了解决方案基本就出来一半了。3. 我的DNS监控方案探测点、探测脚本与告警阈值3.1 为什么监控必须从外部视角做不能只看内部服务器在讲具体方案之前我先说一个原则监控DNS一定要站在“用户视角”去探测而不是只站在自己的服务器上。原因很简单。我们的业务服务器只知道“有没有收到请求”它并不知道用户在抵达之前经历了什么。用户能不能打开页面取决于他所在网络的递归DNS能否正常解析出我们的IP。这台递归DNS不在我们内网它在运营商侧、在企业网络里、在用户家里。所以内部监控天然隔了一层。正确的做法是租用或部署若干台分布在不同区域的探测节点让它们像真实用户一样去执行域名解析把解析结果、解析耗时、成功率实时上报到监控平台。只有从外部视角看才能回答一个核心问题在当下的网络环境里用户能不能通过域名找到我们。3.2 主动探测用Python脚本模拟真实用户解析主动探测是我监控方案里最核心的部分也是投入最小、见效最快的。我用Python的dnspython库写了一个定时任务脚本每60秒跑一次做几件事import dns.resolver import time import json DOMAINS [www.example.com, api.example.com, cdn.example.com] EXPECTED_PREFIX [1.2.3., 4.5.6.] # 按IP段预授权防止精确到IP后频繁误报 DNS_SERVERS [203.0.113.10, 198.51.100.20] # 探针所在网络的两个递归DNS def check_one_domain(domain, dns_server): resolver dns.resolver.Resolver() resolver.nameservers [dns_server] resolver.timeout 3 resolver.lifetime 5 start time.time() try: answers resolver.resolve(domain, A) elapsed_ms (time.time() - start) * 1000 ips [str(r.address) for r in answers] return {domain: domain, dns: dns_server, ips: ips, elapsed_ms: elapsed_ms, ok: True} except Exception as e: elapsed_ms (time.time() - start) * 1000 return {domain: domain, dns: dns_server, ips: [], elapsed_ms: elapsed_ms, ok: False, error: str(e)} results [] for domain in DOMAINS: for server in DNS_SERVERS: result check_one_domain(domain, server) result[time] time.strftime(%Y-%m-%d %H:%M:%S) results.append(result) # 后续代码上报到Prometheus Pushgateway或直接写入InfluxDB print(json.dumps(results, ensure_asciiFalse))这个脚本看起来简单但有三个细节我提醒大家注意第一既要查A记录也要查CNAME解析链。很多业务用的是CNAME形式接入CDNCNAME指向的源域名如果挂掉同样会导致不可用只看A记录会漏掉。第二探测DNS要设置合理的超时。我在脚本里把单次解析超时设为3秒总超时5秒这意味着任何一次解析超过3秒都要被记录为异常。DNS是强实时依赖正常解析通常几十毫秒超过500毫秒用户已经能感知到加载变慢。第三判断“解析结果是否正确”不能只检查有没有返回IP还要校验IP是否属于预期范围。有一天我们某个域名的解析结果返回了一组完全陌生的IP脚本立刻判断为异常后来查明是域名被错误迁移到另一家CDN配置上。如果不做IP校验只要“有结果”就认为正常这类问题就会漏掉。3.3 探测点怎么选多地域、多运营商、多递归解析器缺一不可我把探测点分成三类云端探测节点、办公室或家庭宽带节点、以及机房本地节点。每个类别的作用不同不能互相替代。云端节点放在多个不同区域的数据中心负责提供相对稳定的基准数据。它们的网络质量比较好一般不会因为办公网络波动产生误报但它们也代表了“云端的用户”。办公室和家庭宽带节点覆盖了真实用户所在的网络环境能发现某些地区运营商递归DNS存在的缓存问题。机房本地节点则负责验证权威层自身是否可达。另外很重要的一点同一个探测节点上至少要同时配置两个不同的递归解析器比如一个用节点所在运营商默认DNS一个用公共递归DNS。因为如果只监控一个递归解析器它自己挂了或者缓存坏了你分不清到底是自己的域名坏了还是这个递归解析器坏了。两组数据一对比就能快速归因。最佳实践是每个区域至少部署3个探测节点区域间物理隔离最好是不同云厂商、不同机房。这样就算某个云厂商整体网络抖动也不会造成监控本身失明。3.4 关键指标与告警阈值参考我长期维护的告警规则主要有四条都是经历过实践调整的可以给大家做个参考指标计算方式告警阈值推荐周期解析成功率成功解析次数 / 总尝试次数低于95%持续2分钟60秒/次解析耗时P95最近10分钟所有解析耗时的95分位高于800ms持续5分钟60秒/次权威服务器超时直接探测权威NS的超时次数连续3次超时30秒/次解析结果漂移同一域名不同探测点返回IP不一致出现非预期IP60秒/次特别注意解析成功率阈值不要一开始就设成99.9%因为本地网络抖动、某次探测脚本执行环境被限流都很容易造成单次失败。我一开始把阈值设成99%结果一周收到20多次误报后来改成95%并加了“持续2分钟”这个条件情况才稳定下来。DNS监控要的是“确实发生故障时一定报警”而不是“任何风吹草动都报警”不然值班的人很快就对告警失去信任了。配置报警通知时也要分级。影响所有域名、所有探测点的解析失败是P1直接电话联系值班人影响单个域名或单个区域的解析异常是P2通过IM推送即可只是解析耗时升高但成功率正常属于P3走工单流程观察即可。分级的意义是让不同严重等级的故障用不同节奏处理避免真正的重大故障被淹没在一堆琐碎告警里。4. 收到告警之后怎么做一条可复现的DNS故障排查链路4.1 第一步先确定影响范围而不是直接登录服务器告警一响很多人的第一反应是打开服务器面板看进程、看日志这个习惯在DNS故障场景下是低效的。我现在的第一件事永远是确认影响范围是只有我们域名解析失败还是整个探测网络都解析失败是某一个区域失败还是所有区域都失败方法也很简单看监控面板上几个探测节点的解析情况如果在多个不同网络环境下的探测点都失败了问题大概率出在权威层或域名本身如果只有一个区域失败那更可能是该区域的递归服务商出了问题。还有个更快的土办法让不同地方的同事帮忙在浏览器或命令行里解析同一个域名。如果一个人失败、另一个人正常立刻就能判断是局部性问题不用急着升级全部资源。4.2 第二步用dig命令逐层拆解解析链路确定影响范围之后我会在一台能正常上网的机器上执行下面这一串命令每一层都看一遍# 先看当前系统用的DNS返回什么 dig www.example.com # 绕过本地缓存看一下系统配置的DNS返回的TTL和结果 dig www.example.com 203.0.113.10 noall answer # 看权威服务器到底怎么回答模拟真实用户递归的第一步 dig www.example.com trace # 直接查权威服务器确认权威层本身是否正常 dig www.example.com ns1.example.com noall answer # 检查NS记录是否正常 dig example.com NS short # 检查CNAME解析链 dig www.example.com CNAME short这里面“trace”是最有价值的一步它会一步步列出从根服务器到权威服务器的完整迭代过程。哪一步超时、哪一步返回SERVFAIL故障位置基本就显形了。我见过不少排查半天的人其实只要执行一次trace就能发现自己管理的域名根本没人维护NS记录了。如果trace全程正常但用系统默认DNS解析失败那就锁定是递归层的问题。更具体的判断依据是换一个公共DNS执行同样的查询如果立刻成功故障几乎可以确定在原来的递归服务器上。4.3 第三步结合TTL和域名变更时间推断根因解析链路没查出问题但用户仍然反馈异常这时候要把视角拉回到“最近发生了什么变化”。我会重点看两件事最近一次DNS变更是什么时候改了哪些记录以及当前解析结果的TTL还剩多久。DNS故障的恢复时间几乎总是和TTL绑定的。假如一个域名原来的TTL是300秒故障记录在15分钟前已经被写入递归缓存那么即使在10分钟前已经修复了权威记录仍有5分钟左右的旧缓存残留。这不是配置错了而是系统机制天然决定的。所以排查时看到解析结果“一会儿好一会儿坏”先算一下TTL窗口别急着反复改配置否则越改越乱。另外要核对变更时间线。几乎所有人为造成的DNS问题都能追溯到一次“看起来没问题”的变更。我把每次DNS修改前后的完整解析结果快照都保留下来了遇到问题直接对比快照一眼能看出是哪个字段变了。很多团队没有这个习惯出了问题只能翻聊天记录和操作日志既慢又容易漏。强烈建议至少在每次变更前自动跑一轮全量域名解析把结果存成JSON存档。4.4 恢复动作与值班操作清单故障定位完成之后恢复动作要尽量提前准备好。按照故障层不同我的操作清单大致是故障层操作动作备注权威服务器宕机切换备用NS或把权威托管迁移到备用平台切换前确保备用NS已有完整记录权威记录配置错误回滚到变更前的解析快照确认旧记录对应的IP仍可用递归缓存污染联系对应递归服务商刷新缓存同时页面引导用户换DNS只能等TTL过期急也没用业务侧割接不同步完整发布DNS记录等待全量生效复盘割接流程确认DNS与业务同频DNSSEC问题重新生成签名并发布DNSSEC签名更新要预留时间窗口还有一个常被忽略的动作恢复之后不要马上关掉告警而是继续观察一个完整的TTL周期。比如域名TTL是300秒就在告警恢复后再观察5分钟确认所有探测点的解析结果都稳定指向预期IP才算真正闭环。我见过很多人看到监控面板恢复绿色就宣布故障结束结果没多久另一个区域的用户又反馈打不开其实就是因为旧缓存还在影响部分地区。5. 想在故障之前避免被动日常演练与DNS变更管控5.1 故障注入演练让DNS异常在测试环境先发生没有演练过的故障预案基本等于没有预案。DNS相关的故障尤其值得演练因为它的症状和根因之间隔了好几层抽象不实际经历一次很难建立起直觉。我的做法是每个季度做一次故障注入。在测试环境里用防火墙规则临时把权威DNS服务器的53端口流量全部丢弃模拟权威服务器不可达再设置一个模拟递归服务器把它对某个特定域名的查询结果改成返回NXDOMAIN模拟错误记录还可以把TTL临时改成非常小的值模拟配置参数导致的解析抖动。演练过程中要求值班同学严格按照实际告警流程走一遍收到告警、确定范围、执行dig排查、定位到层、尝试恢复、记录复盘文档。这一步看起来麻烦但真到了生产故障时价值完全是翻倍的。因为绝大多数人在紧张状态下会条件反射地重复检查已经查过的地方演练提前把所有可能“绕路”的地方都踩过一遍真出问题时就能直接走最短路径。5.2 把DNS变更纳入发布流程而不是临时改一笔DNS变更很容易被当成“改一行配置”的小事但它一旦出错影响面是全局的。我一直建议团队在内部把DNS变更当成一次正式发布来管理提前在变更单里写明域名、变更内容、影响范围、生效时间、回滚方案并且要求变更窗口内留出观察时间。在技术执行层面有三个强制动作值得坚持。第一所有变更必须基于当前解析快照操作严禁靠记忆直接改记录。第二变更完成后立即执行一轮全量解析校验对比变更前后结果确认预期记录已生效其他记录没有被误伤。第三每次变更后把配置文件或操作命令存档并注明变更原因和负责人。这样做的目的不是增加流程负担而是为了给“事后复盘”留下唯一可信的数据源。5.3 持续监控之外的最后一个习惯定期核查DNS配置本身最后再分享一个让我少踩很多坑的习惯每个月抽一点时间主动核查一遍DNS配置本身的正确性。重点看几项域名NS记录是否指向预期服务器DNSSEC签名是否即将过期MX记录和TXT记录有没有被误改子域名的CNAME链是否完整以及历史遗留的“已经不再使用的解析记录”有没有清理。这些静态检查不依赖监控告警纯粹靠定期巡检发现但能提前阻止很多潜在问题。我做DNS监控和运维这些年最大的体会是DNS问题之所以难以处理最重要的原因不是技术复杂而是它平时太透明透明到大家都默认它不会出问题。等到问题真的爆发才发现监控体系里根本没有覆盖这一层。用外部探针、分层告警、故障演练、变更管控这几个动作组合起来至少能在故障真正发生之前发现得早一点、定位得快一点、心里稳一点。这个“提前量”对在线业务意味着什么经历过的人自然懂。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。