跳转到主内容DNS | 物联网民工

DNS

线上改完一条 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 记录未过期,直接命中最终缓存
  • 即使最终记录过期了,.comexample.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 排障先看这四层:

  1. 客户端问的是哪个递归解析器
  2. 递归解析器返回的是缓存、委派,还是最终答案
  3. 权威服务器当前返回什么
  4. TTL 或负缓存是否还在生效

做域名变更时,别只看“配置已保存”

域名切流、迁移和回滚时,最危险的默认假设,是权威一改,外界就立刻一致。

更稳的做法是提前把时间因素算进去:

  • 变更前先降低相关记录 TTL
  • 等旧 TTL 自然消化后再切换核心记录
  • 同时检查父区委派、子区权威和实际服务地址
  • 回滚时同样考虑旧答案和负缓存残留
  • 用多个递归解析器和直接权威查询分别验证

DNS 变更真正完成,不是控制台显示保存成功,而是外部观察点都收敛到预期答案。

DNS 最值得记住的不是 A / AAAA / CNAME / NS 这些记录名,而是:它用分层委派解决命名权,用递归解析器吸收查询复杂度,用 TTL 管理全网可以接受的不一致窗口。

继续阅读

  • DNS 污染:为什么错误答案会先一步进入解析链路
  • DNSSEC:DNS 答案为什么需要能被验证
  • DoH / DoT:DNS 第一跳的传输路径和信任边界怎么变
  • UDP:为什么经典 DNS 还大量跑在 UDP 上