DNS故障排查与监控实战:从原理到告警SOP
作为常年跟线上故障打交道的运维我最大的感受就是DNS问题是最让人头疼的“隐形杀手”。表面上看用户访问不了服务监控面板上数据库、缓存、带宽全都正常但服务就是进不去。前几天某知名国际化社交平台出现的大规模访问异常官方定位到域名解析系统出现问题恰好就是我踩过无数次的坑。今天就把这套如何及时发现DNS问题、快速定位根因的方法完整写出来希望对正在搭建监控体系或者每次出故障都手忙脚乱的同学有帮助。DNS的全称是域名系统它负责把用户输入的网址翻译成服务器IP地址。你可以把它理解成互联网世界的电话簿。一旦这本电话簿出了问题用户就像拿到了一个错号或者空号你再怎么优化电话线路都没用。很多团队在监控上投入了大量精力去做应用层、基础设施层的告警却容易忽略DNS这个最前置的环节。实际上DNS故障造成的业务影响往往是全站级别的比单个机房断网还要可怕。这篇内容适合正在做运维监控、SRE、后端开发的同学也适合独立站站长、想建立自己业务可观测体系的人。我会从现象背后的原理讲起把排查命令、监控指标、告警规则、应急SOP全部串联起来每一步都给出可落地的配置和参数。文章里我会统一使用“目标站点”和“某社交平台”这类代称域名也使用example.com做演示。1. 从一次大规模宕机看DNS故障的破坏力1.1 表面是“网站打不开”本质是域名解析失效那次宕机的典型表现是全球范围内大量用户刷新页面时提示“无法访问此网站”或者等待很久之后出现“连接已重置”。直接看业务监控HTTP错误率直线飙升但奇怪的是边缘节点、负载均衡器的CPU和带宽都处于低水位状态后端的数据库和Redis也没有明显热点。所有证据都指向一个方向流量根本没有到达业务服务器。这种“服务器很闲但用户进不来”的矛盾是DNS故障最典型的特征。域名解析一旦失败用户的浏览器或者App根本拿不到IP地址自然没办法发起TCP连接。此时你再检查后端进程是否存活、JVM内存是否溢出都是白费功夫。随后技术人员通过公共DNS服务商的检测工具发现该域名在全球多个地区的权威解析服务器返回异常部分请求超时部分请求被错误指向了错误地址。这就导致即使故障持续了几十分钟很多内部监控系统依然认为“一切正常”。为什么因为内部监控通常绕过了本地DNS而直接用IP地址访问服务或者使用了内部的解析服务器恰好没被波及。1.2 为什么DNS故障容易被误判为后端问题我们来还原一般团队的排查路径。用户反馈无法访问运维第一反应去看负载均衡的流量曲线发现流量确实掉了一半以上。于是开始怀疑后端服务挂了登录服务器查进程、看日志结果一切正常。接着怀疑网络出口丢包登录路由器ping了一圈延迟正常丢包率接近零。到这里很多人会陷入“该查的都查了”的死胡同。问题的根源在于常规监控很难覆盖“域名解析正确性”这个维度。你监控了服务器存活、监控了业务接口延迟、监控了数据库连接池但你没有监控“用户拿到IP是否正确”以及“权威服务器是否响应”。这两件事恰恰是DNS故障的核心。更隐蔽的是DNS故障并不总是“完全失效”。它可能是部分区域失效、缓存污染、TTL期间内错误记录甚至只影响特定网络运营商。这种“看起来能用但偶尔不行”的现象比全挂更让人抓狂。我见过一个案例某个域名在A运营商网络下解析正常在B运营商网络下却返回了一个早已下线的旧机房IP导致部分用户持续报错排查了整整一个下午。所以想要及时发现DNS问题第一步不是买工具而是建立“DNS是一个独立故障域”的认知。它和你的应用服务同样重要需要独立监控、独立告警、独立应急。如果这个认知不到位后面所有的技术方案都会搭错地基。2. 排查DNS问题的基本功从客户端到权威服务器的完整链路2.1 手动探测的必备命令与参数当你怀疑DNS异常时第一步是确认当前解析结果。在Linux终端里我习惯先跑一条带“trace”的dig命令把从根服务器到权威服务器的完整解析路径打出来。dig trace www.example.com这条命令会依次显示根服务器返回的顶级域名服务器地址、顶级域名服务器返回的权威服务器地址以及最终权威服务器返回的A记录。如果其中某一步出现“connection timed out; no servers could be reached”问题基本就定位在了那个层级。相比直接执行dig查询它能帮你迅速判断是本地递归服务器的问题、还是上游权威服务器的问题。如果你是在非Linux环境下也可以用nslookup。但要注意nslookup输出里的“Server”指的是你当前使用的递归解析器它给出的Non-authoritative answer是缓存结果。想要绕过缓存直接查权威服务器需要指定server参数nslookup -serverns1.example.com www.example.com这和直接用dig 指定权威服务器是同一个道理。实际排查时我一般会同时查询三个不同位置的解析源本机配置的DNS、公共DNS、目标域名的权威服务器。三者的结果如果出现不一致那就说明问题出在递归解析链路或者权威同步策略上。2.2 分层拆解递归解析器、权威服务器、TTL与传播延迟DNS解析链路可以简化成两个核心角色。递归解析器负责帮客户端四处打听它可能是你的内部DNS服务也可能是运营商分配的地址或者公共DNS权威服务器则是域名DNS记录的最终发布者一般由域名注册商、云解析服务商提供。用户访问一个域名时首先向递归解析器发起查询递归解析器再通过逐级询问的方式找到对应的权威服务器并拿到最终答案。这里有一个关键的“死缓”机制——TTLTime To Live生存时间。递归解析器拿到DNS记录后会在本地缓存一段时间时间长短由TTL决定。如果某条A记录的TTL设置为600秒意味着重新向权威服务器发起查询至少要等10分钟。在突发故障时这种缓存让很多用户仍然拿着旧IP访问服务而如果权威服务器发出的错误记录TTL设置得过长错误就会被大量终端长期缓存故障恢复后依然会有一部分用户持续访问旧地址。我在排查时常用下面这个表格来对应症状和可疑层级症状可能问题层优先检查手段所有区域全部解析失败dig超时本地递归服务或网络出口检查本机DNS配置换公共DNS对比部分区域失败另一部分正常权威服务器分区域故障或调度策略异常用不同地区的探测点分别解析解析结果返回旧IP或错误IPDNS记录被篡改或缓存未失效对比权威结果与公共递归结果重点看TTL内部服务域名正常公网域名异常内部DNS与公网DNS割裂或防火墙规则检查内网转发策略和云解析配置这里想强调的是TTL这个参数。它不只影响故障恢复速度也直接影响你的监控策略设计。如果你的监控脚本直接向权威服务器查询而你实际业务使用的是递归缓存那么监控报告“解析正常”时用户拿到的可能还是旧数据。所以在做监控时我从不只盯权威服务器还会从多地域的探测节点发起真实递归查询模拟用户的实际访问路径这样才能看到用户眼中真实的世界。3. 建立一套能自动发现DNS异常的健康监控体系3.1 三个必须监控的分层指标单纯靠人肉dig不够系统化监控需要覆盖三个维度可用性、正确性、性能。可用性比较好理解就是权威服务器能不能正常响应。我们可以用脚本或者开源探活工具定期向权威服务器发起查询判断返回的RCODE值是否为NOERROR。如果出现SERVFAIL、NXDOMAIN或者查询超时就要立刻告警。这个监控的采集周期我建议在30秒到1分钟之间因为DNS故障影响面太大30秒的空白期都可能造成大规模损失。正确性监控则要对比“实际解析结果”和“预期解析结果”。比如业务域名的A记录应该指向负载均衡的VIP如果某个时刻解析出来变成了一个未知IP无论返回码是不是NOERROR都属于严重故障。另一种做法是多地域对比从华东、华北、华南、西南等不同节点解析同一个域名正常情况这些节点拿到的结果应该一致或符合调度规则。如果出现明显的地域分裂就很可能是解析智能调度出错了。性能监控这条线经常被忽略。DNS解析本身是毫秒级操作正常情况下递归解析在20到50毫秒内完成权威查询更是在个位数毫秒级别。一旦解析时间飙到几百毫秒甚至超时虽然页面最终还能打开用户感知到的却是明显的卡顿。这种性能劣化往往是网络抖动、DNS服务器过载的前兆值得单独设置一条告警线。3.2 用开源工具搭建低成本监控方案很多人第一反应是上商业化监控产品但我觉得在初期利用开源的Prometheus生态完全可以跑起来成本低、自主可控、数据完全在自己的掌控中。核心思路是用blackbox_exporter的dns探针作为采集器配合Prometheus的规则做告警。exporter的配置里需要定义一个DNS探测模块然后指定要监控的域名和查询类型modules: dns_tcp: prober: dns dns: transport_protocol: tcp query_name: www.example.com query_type: A valid_rcodes: - NOERROR配置好采集模块后在Prometheus里新建一条告警规则。比如当DNS查询失败或者响应时间超过3秒时触发Critical告警groups: - name: dns_alerts rules: - alert: DnsProbeFailed expr: probe_success{jobdns_monitor} 0 for: 1m labels: severity: critical annotations: summary: DNS探测失败 {{ $labels.instance }} - alert: DnsProbeSlow expr: probe_duration_seconds{jobdns_monitor} 3 for: 2m labels: severity: warning annotations: summary: DNS解析超过3秒 {{ $labels.instance }}为了让监控结果更接近真实用户我会在exporter的探测目标里同时配置三个递归服务器源本机所在IDC的内部DNS、一家公共DNS、目标站点主域名的权威服务器。三个源的结果会形成一张多维对比视图只要有一个源的数据异常就能迅速看到差异。这在平时是发现“运营商缓存脏数据”的神器有一次我们用公共DNS解析全部正常但通过某个本地运营商源解析却得到了一个过期IP靠这种方式一晚上就定位到了问题源头。3.3 告警阈值怎么设才能不炸群又不漏报DNS问题往往是全局性的所以告警阈值要尽量保守宁可多一点确认时间也不要因为一次抖动就把全组人半夜叫醒。我个人的实践是这样的解析失败类告警持续1分钟且连续3次探测失败才触发Critical延迟类告警则要看历史基线比如正常情况下P99延迟是30毫秒那超过3倍基线并持续5分钟才算异常。这里想特别提醒一句不要对所有域名使用同一套告警阈值。你的核心业务域名、用于内部跳转的域名、静态资源CDN域名它们的重要程度和容忍度完全不同。我会把域名分为P0、P1、P2三级P0域名比如登录、支付、首页用最激进的阈值P2域名比如活动页、帮助中心可以适当放宽避免告警疲劳。同时告警里必须携带“当前解析结果”和“预期结果”这样值班同学接到告警的第一时间就知道差异在哪而不是先登录服务器跑命令。我见过太多告警邮件只写了“域名解析失败”五个字收到的人根本不知道该干嘛。好的监控不仅是发现问题还得帮人节省定位时间。4. 实战DNS故障应急响应的完整流程4.1 从接到告警到恢复业务的分步SOP一旦告警触发我会建议按照下面的顺序操作每一步都有明确目的可以最大程度减少混乱。第一步立即确认影响面。用多地域探测工具同时解析出问题的域名对比不同地域、不同运营商的结果判断是全局故障还是部分区域故障。这个信息决定了后续动作是“切流量”还是“改解析”。第二步切换解析服务商或强制刷新缓存。如果权威服务器本身无响应或者响应异常最快的临时方案是在云解析控制台将域名切换到备用解析服务商前提是你提前在多个服务商维护了完全一致的记录。如果没有备用方案就只能等待权威服务商恢复此时需要不停刷新你内部DNS服务器的缓存同时观察公共DNS的缓存情况。我建议内部递归服务器执行“flush”命令并临时调低高级别域名的TTL值让错误记录尽快过期。第三步如果确认是DNS记录被污染或是错误内容赶紧用权威服务器管理工具修改记录把所有A记录、CNAME、MX记录逐一核实一遍尤其是旧的机房IP、测试IP这类历史残留。改完之后用dig 权威服务器查看最新的值确认已经生效。第四步也是很多人会漏掉的要持续监控到“缓存完全过期”才算真正恢复。比如旧记录的TTL是600秒那么最后一批用户拿到新地址至少需要等到600秒之后。恢复阶段绝不能只看权威服务器状态必须同时观察公共DNS的解析值是否已经替换为新地址。在实际操作中我会写一个简单的脚本来做恢复验证循环查询各个公共DNS节点直到所有节点的结果都符合预期for ns in 1.1.1.1 8.8.8.8 119.29.29.29; do echo $ns dig $ns www.example.com A short time2 tries1 done“time2 tries1”这两个参数是严格控制单次查询的超时时间防止脚本卡在某个不响应的服务器上非常适合故障恢复阶段循环检查。4.2 常见的三个定位误区排查DNS问题时我观察很多团队会踩进三只坑里。第一只坑是“ping通了就以为DNS没问题”。ping走的是ICMP协议你ping域名时确实会触发解析但ping命令成功只代表解析拿到了一个IP不保证这个IP是正确的、是当前最新的。如果你想验证解析正确性一定要对比解析结果和已知IP而不是看ICMP通不通。第二只坑是“只顾改正没考虑TTL”。不少人发现记录错了改完之后扭头就去处理其他事情结果过了半小时用户还在报障。原因就是TTL没改旧记录在运营商缓存里又存活了一段时间。正确做法是改动故障记录之前先把TTL临时调小到60秒甚至30秒等全面生效后再调回正常值。这个操作要提前做而不是故障恢复后做。第三只坑是“只监控一本权威域名”。大点的系统往往有多个域名甚至同一域名有多个权威DNS服务商。只监控其中一家可能会漏掉故障时另一家状态的问题。我一般会至少监控两份权威服务器并且要求两份结果完全一致否则就进入变更流程排查原因。4.3 应急演练平时不演练故障时一定手忙脚乱DNS故障和机房断电一样平时永远不会觉得有必要一旦真的发生全场乱成一团。我建议每季度做一次小规模演练在测试环境或者灰度环境里人为把权威解析记录改成错误值然后让整个值班流程真实跑一遍。重点看三件事监控是否能在1分钟内发现、告警是否准确指向DNS原因、值班同学能否在5分钟内找到切换入口。第一次演练大概率会暴露很多问题比如告警规则里漏了某些子域名或者切换脚本里账号没有配好权限。这些问题早发现代价极小真到故障现场才发现代价就是全站业务受损。我经历过一次值班为演练准备的备用服务商账号居然早就被自动轮换密码脚本改了密码还好当时只是演练否则后果不堪设想。5. 日常DNS健康维护与避坑经验5.1 记录TTL规划平衡性能与恢复速度TTL不是越大越快而是要在性能和故障恢复速度之间做取舍。很多团队为了减少查询量把TTL设置成86400秒也就是一天。这么做的好处是减轻权威服务器压力坏处是记录出错后全网缓存最长要一天才能清洗干净这基本等于宣告当天业务不可恢复。我通常把核心域名的A记录TTL设置在300秒到600秒之间静态资源CDN域名可以放宽到1800秒那条用来做容灾切换的域名则长期保持60秒。这样每次切流或者变更最快1分钟就能让大部分递归服务器拿到新记录。至于流量压力现代DNS解析服务器面对这点查询量完全扛得住不需要刻意拉高TTL。5.2 配置变更前必须做的对比检查DNS记录变更看似简单实际风险极高。我见过有人改一条CNAME时手滑删掉了同名的A记录导致整个子域不可解析。后来我定了一条规矩任何变更前先导出一份现有解析记录完整备份到本地变更完成后马上对比新增和删除的条目。线上的差异比对用脚本自动跑不允许人工肉眼对比。变更时还要特别注意“先加后删”原则。比如要更换源站IP先把新IP的解析记录加上等确认全链路解析正常再去删除旧IP。有些同学图省事直接修改记录覆盖旧值如果新值填错了DNS的TTL机制会让错误迅速扩散到全网想回退也很难快速生效。5.3 完善的可观测性量化和可视化结合最后想说一下可观测性的终极形态。虽然Prometheus加blackbox_exporter已经能帮我告警但为了直观看到问题我还习惯把DNS解析指标接入业务监控大盘。展示的内容包括四个核心曲线权威服务器响应时间、递归解析成功率、解析结果正确性系数、各地域解析差异。这样做的好处是一旦出现相关告警值班同学第一眼就能从全局视角判断影响范围而不是在命令行里逐个敲dig。我目前看到的很多团队其实不缺工具也不缺技术人才缺的是把DNS当作独立故障域来运维的意识。下一次当你再遇到全站无法访问后端一切正常试着先跑一次dig。你会发现真相往往藏在最不起眼的地方。每次处理完这类故障我都有一个习惯就是把当天的异常现象、告警截图、解析结果对比全部写进一份复盘文档特别标注哪些环节是因为监控盲区导致延长了发现时间。几次下来你的监控体系会变得越来越聪明。说到底DNS问题的核心不是“修不修得好”而是“发现得够不够快”。快一步业务就稳一分。