线上改完一条 A 记录,浏览器还在连旧地址;权威服务器已经返回了新结果,不同地区的用户却继续看到不一样的答案;抓包里明明问的是 www.example.com,前几跳响应却都没有直接给出 IP。
DNS 难理解的地方不在记录类型,而在它背后的模型:它从来不是一张全网实时查找表,而是靠分层委派、递归追问和带 TTL 的缓存共同维持的解析系统。
名字空间分层委派
递归解析器替客户端逐层追问
查询结果按 TTL 缓存
全网接受一段时间内的不一致
DNS 变更的关键问题不是“权威服务器有没有改对”,而是“外部观察点什么时候会从旧答案收敛到新答案”。
一次解析到底发生了什么
应用要访问 www.example.com 时,不会自己从根服务器一路问到最终权威服务器。它先把问题交给本机的轻量解析端,再由配置好的递归解析器把后面的路走完。
Client
-> Recursive Resolver: www.example.com A ?
Recursive Resolver
-> Root Server: www.example.com A ?
Root Server
-> Recursive Resolver: 我不知道最终答案,但 .com 去问这些服务器
Recursive Resolver
-> .com TLD Server: www.example.com A ?
.com TLD Server
-> Recursive Resolver: 我不知道最终答案,但 example.com 去问这些权威服务器
Recursive Resolver
-> Authoritative Server for example.com: www.example.com A ?
Authoritative Server
-> Recursive Resolver: www.example.com A = 93.184.216.34, TTL = ...
Recursive Resolver
-> Client: www.example.com A = 93.184.216.34, TTL 剩余时间 = ...
这条路径里,最后那个权威服务器提供最终业务数据,前面几层只负责“指路”。
前面两跳都没有直接回答“结果是什么”:
- 根服务器回答的是“
.com这段该问谁” .com回答的是“example.com这段该问谁”- 只有
example.com的权威服务器才真正回答www.example.com是什么
这条路径对应 DNS 的三个核心设计:
- 逐层委派,而不是全局集中存储
- 递归解析器负责把路走完,而不是让客户端自己追
- 每一跳得到的线索和最终答案都可以按 TTL 缓存
第二次再查 www.example.com 时,递归解析器不用重走整条链:
- 最终
A记录未过期,直接命中最终缓存 - 即使最终记录过期了,
.com和example.com的委派信息还在缓存里 - 需要重问的只是链路里的后半段
所以 DNS 的性能不只是“权威服务器答得快”,也来自“绝大多数查询不需要每次都从根重新开始”。
先看这几个对象
Stub Resolver:应用或主机上的轻量解析端,只负责把问题交出去Recursive Resolver:替客户端把问题查到底,并维护缓存Authoritative Server:对某个 zone 拥有最终回答权Root / TLD / 下级权威:按层级把名字空间逐段委派下去Zone:某个管理边界内、由一组权威服务器负责的数据集合TTL:解析结果的可缓存时长,不是永久真理Recursive Query:客户端把“帮我查到底”这件事委托给递归解析器Iterative Query:递归解析器在上游之间逐步追问,每次拿一段线索再继续
客户端视角看到的是递归服务,递归解析器内部运行的是迭代查找逻辑。把这两个层次分开,很多抓包现象就能对应起来。
DNS 首先解决的是命名权分配
网络规模很小时,主机名和地址可以写在一张本地表里。早期互联网也确实用过类似方式。
但规模一上来,这种方式会很快失控:
- 全网目录越来越大,分发成本越来越高
- 每个组织都要频繁改自己的那部分记录
- 地址变化后,旧表会在各处残留
- 没有自然的管理边界,权限很难下放
DNS 看起来像查表,真正解决的是命名权分配。
com 不需要知道 example.com 里的每一条主机记录;example.com 也不需要把每次子域记录变更上报给一个全网中心节点。上层只需要知道下一层谁负责。
委派的价值是:
全局名字规则保持统一
局部名字空间交给对应组织自治
查询者不用预先知道全网数据放在哪里
DNS 因此比一张全局表复杂,但也因此能在跨组织、跨地区、持续变化的互联网里工作。
递归解析器不是简单转发
客户端只知道自己配置了一个 DNS 服务器,很容易把递归解析器理解成“转发请求的中间人”。
它实际承担更多事情:
- 替客户端走完整条委派链
- 缓存最终答案
- 缓存中间委派信息
- 处理超时、重试、截断和上游失败
- 把复杂查询过程收敛到少数基础设施上
同一个域名,在不同网络里会看到不同结果。
不同递归解析器的缓存状态不同,上游路径不同,策略也不同。客户端拿到的是“当前递归解析器相信的答案”,不是权威服务器刚刚更新后的状态。
排障时,先分清:
- 客户端问的是哪个递归解析器
- 递归解析器返回的是缓存答案还是新查答案
- 问到权威服务器时看到的又是什么
只在本机 ping 一下域名,不足以判断 DNS 源头是否正确。
TTL 管理的是不一致窗口
DNS 里最关键的时间参数是 TTL。
它不是装饰字段,也不是性能优化。TTL 表达的是:
这条答案在一段时间内可以被缓存和复用
TTL 越长:
- 缓存命中越高
- 权威服务器压力越小
- 查询延迟更稳定
- 变更传播越慢
TTL 越短:
- 变更收敛更快
- 查询量更大
- 上游抖动会被放大
DNS 选择的是软状态:在有限时间内接受旧答案,以换取可扩展性和可用性。
这解释了线上现象:
- 权威服务器已经改了,递归缓存还没过期
- A 地用户已经看到新地址,B 地用户还在访问旧地址
- 回滚配置后,仍有用户继续命中之前缓存的错误答案
这不说明 DNS 坏了。它还在 TTL 允许的不一致窗口里。
负缓存也会让“刚加的记录”看不见
DNS 不只缓存“查到了什么”,也会缓存“暂时查不到什么”。
如果某个名字之前查到的是 NXDOMAIN,递归解析器会在一段时间内缓存这个否定结果。之后你把记录补上,也不代表所有递归解析器会立刻重新查询权威。
这类问题现场很常见:
- 先访问了一个还没创建的域名
- 递归解析器缓存了不存在结果
- 运维随后补上记录
- 部分用户仍然继续看到不存在
所以 DNS 变更排障时,不能只看正向记录的 TTL,还要考虑失败结果是否被缓存过。
Zone 和域名不是一回事
Domain Name 是命名树里的名字,Zone 是授权和管理边界。
这两个对象相关,但不能混为一谈。
例如 api.prod.example.com 只是 example.com 下面的一段名字,但它可以被委派给另一组权威服务器管理。一旦子域被委派出去,父区负责的不是子域里的最终业务记录,而是“这段该去问谁”。
配置错误都出在这里:
- 父区有委派,子区权威没配好
- 子区已经切走,排障的人还在父区里找最终记录
- glue、NS 和权威数据不一致
- 看到名字层级相似,就误以为管理边界相同
判断 DNS 问题时,先确认自己正在看的到底是父区、子区,还是最终权威。
CNAME 不是万能别名
CNAME 常被理解成“给一个名字加个别名”。这个理解只对了一半。
它表达的是:这个名字本身不是终点,请把整个名字解析过程转向另一个名字。
因此,一个名字如果已经是 CNAME,不能再同时放其他数据记录。否则它一边说“我其实是别人”,一边又说“我自己还有这些数据”,解析语义会混乱。
这就是平台限制根域名直接使用 CNAME 的原因,也是排障时不能只问“这个名字有没有记录”的原因,还要看记录类型之间的语义是否冲突。
UDP 不是 DNS 不可靠的原因
传统 DNS 大量使用 UDP,不是因为它不在乎可靠性,而是因为高频查询很小、很短,请求响应模型适合低成本传输。
UDP 的好处是:
- 不需要建立连接
- 普通查询延迟低
- 服务器更容易承受大量短请求
代价是:
- 大响应会被截断
- 丢包要靠重试处理
- 中间设备会错误处理分片或大包
如果抓包里看到截断、重试、TCP 回退或大响应异常,问题在传输路径上。
线上 DNS 出问题,按层查
| 现象 | 优先入口 |
|---|---|
| 本机查不到,其他网络能查到 | 本机 DNS 配置、递归解析器 |
| 权威正确,用户仍看到旧值 | TTL、递归缓存 |
| 刚创建记录仍返回不存在 | 负缓存、查询的名字是否一致 |
| 子域解析异常 | 父区委派、子区权威、glue |
| 小记录正常,大记录失败 | UDP 截断、TCP 回退、中间设备 |
| 浏览器表现和命令行不同 | 应用缓存、系统缓存、查询类型差异 |
DNS 排障先看这四层:
- 客户端问的是哪个递归解析器
- 递归解析器返回的是缓存、委派,还是最终答案
- 权威服务器当前返回什么
- TTL 或负缓存是否还在生效
做域名变更时,别只看“配置已保存”
域名切流、迁移和回滚时,最危险的默认假设,是权威一改,外界就立刻一致。
更稳的做法是提前把时间因素算进去:
- 变更前先降低相关记录 TTL
- 等旧 TTL 自然消化后再切换核心记录
- 同时检查父区委派、子区权威和实际服务地址
- 回滚时同样考虑旧答案和负缓存残留
- 用多个递归解析器和直接权威查询分别验证
DNS 变更真正完成,不是控制台显示保存成功,而是外部观察点都收敛到预期答案。
DNS 最值得记住的不是 A / AAAA / CNAME / NS 这些记录名,而是:它用分层委派解决命名权,用递归解析器吸收查询复杂度,用 TTL 管理全网可以接受的不一致窗口。