跳到正文

图解 DNS 工作原理:递归解析、缓存与 TTL

跟随一次 DNS 查询,从浏览器经过解析器、根服务器、TLD 服务器到权威服务器,再看缓存、TTL 和否定应答如何影响它。

· 创始人兼开发者

发布于

一台笔记本电脑向递归解析器发出查询。解析器按编号步骤依次询问根服务器、com TLD 服务器和 example.com 的权威服务器,得到两次引荐和一条 TTL 为 300 秒的 A 记录,然后把它返回给笔记本电脑。

你修改了一条 A 记录,运行 dig,看到了新地址。另一个办公室的同事一小时后拿到的仍是旧地址。一个新子域名在你这里能用,在客户那里却返回 NXDOMAIN。这些都不是随机现象:它们源于 DNS 解析和缓存的工作方式,一旦你能画出一次查询经过的路径,就能预测它们。

本文借助一张图,跟随一次查询从浏览器到权威服务器再返回,然后介绍 TTL、否定缓存、委派、传输层以及生产环境中会遇到的故障模式。

每次查询中的四种角色

一次查询最多会经过四类服务器,每一类知道答案的不同部分。

角色 由谁运营 它知道什么
存根解析器 你的操作系统或浏览器 它的递归解析器在哪里,外加一个小型本地缓存
递归解析器 你的 ISP、你的公司,或 1.1.1.1、8.8.8.8 这样的公共服务 起初一无所知;它负责找到答案并缓存
根服务器和 TLD 服务器 根服务器运营方;com 等由 Verisign 这样的注册局运营 下一级标签由谁负责
权威服务器 你自己或你的 DNS 服务商 你的区域中的实际记录

根并不是一台机器。根据 root-servers.org 2026 年 11 月的数据,根服务器共有 13 个身份,从 a 到 m.root-servers.net,由 12 个独立组织运营,借助任播分布在全球 2,000 多个实例上。

逐步拆解一次查询

假设你的浏览器需要解析 app.example.com,而且各处都没有缓存:

  1. 浏览器先检查自己的缓存,然后询问操作系统的存根解析器。
  2. 存根解析器向配置好的递归解析器发送一个带有“recursion desired”标志的查询:app.example.com 的 A 记录是什么?
  3. 解析器没有任何缓存,于是询问一台根服务器。根服务器不知道答案,但知道谁负责 com,于是返回一次引荐(referral):com 的 NS 记录及其地址(胶水记录)。
  4. 解析器询问一台 com TLD 服务器,后者返回另一次引荐:example.com 的域名服务器。
  5. 解析器询问其中一台权威服务器,后者返回答案:app.example.com. 300 IN A 203.0.113.10。
  6. 解析器把学到的每条记录按其 TTL 缓存起来,并把答案返回给存根解析器,再由它交给浏览器。

存根解析器发出的是递归查询:它要的是最终答案。解析器发出的是迭代查询:每台服务器要么返回答案,要么指向更接近答案的服务器。根服务器和 TLD 服务器从不替你追查答案。

你可以用 dig +trace 观察迭代过程,它从根服务器开始查询,而不是使用你的解析器缓存(输出已精简):

$ dig +trace app.example.com
.                  518400  IN  NS  a.root-servers.net.
com.               172800  IN  NS  a.gtld-servers.net.
example.com.       172800  IN  NS  ns1.example.net.
app.example.com.   300     IN  A   203.0.113.10

现代解析器还会采用 QNAME 最小化(RFC 9156):只向根服务器询问 com,只向 TLD 服务器询问 example.com,这样上层服务器永远看不到你查询的完整名称。

缓存与 TTL

每条记录都带有以秒为单位的生存时间(TTL)。一个以 TTL 300 缓存了 app.example.com 的解析器,会在接下来的五分钟里倒计时地从缓存中应答,直到过期后才再次询问权威服务器。浏览器和操作系统还会在此之上维护各自的短期缓存。

这就是人们所说的“传播”。修改记录时,并没有任何东西被推送到别处。每个缓存了旧值的解析器都会继续返回旧值,直到它的副本过期;所以最坏情况大致取决于旧的 TTL,而不是新的 TTL。解析器还会截断过长的 TTL:例如 Unbound 默认把缓存记录的上限设为一天。

变更时的实用规则:

  • 在计划内的变更之前先调低 TTL。 如果一条记录的 TTL 是 86400,就在迁移前至少一天把它改成 300,等旧 TTL 过去后再做变更,然后再把 TTL 调回去。
  • 只在需要快速故障切换的地方使用短 TTL。 60 秒的 TTL 意味着对服务商的查询更多,用户的缓存未命中也更多,而每次未命中都要付出一次完整解析的代价。
  • 更换域名服务器更慢。 父区域中 example.com 的 NS 记录有自己的 TTL,在 com 中是 172800 秒(两天),而且你无法缩短它。

基于 DNS 的故障切换取决于这些数字。AWS 多区域架构图和灾难恢复架构图展示了带健康检查的 DNS 记录处在什么位置,以及为什么它的 TTL 决定了恢复时间的上限。

否定缓存:NXDOMAIN 陷阱

解析器也会缓存“不存在”。当某个名称不存在时,权威服务器会返回 NXDOMAIN 以及该区域的 SOA 记录,解析器会按 SOA 记录的 TTL 与其 MINIMUM 字段中较小的那个值来缓存这个否定应答(RFC 2308)。

典型的故障是这样的:有人在记录创建之前查询了 api.example.com,某个解析器把 NXDOMAIN 缓存了一小时;你随后创建了记录,而这个解析器在一小时结束前会一直说它不存在。在公布新主机名之前,先用 dig example.com SOA 检查否定 TTL,并且在任何人测试之前就把记录建好。

委派、胶水记录与残缺服务器

一个区域之所以存在于 DNS 中,是因为它的父区域把它委派了出来。com 区域保存着 NS 记录,说明哪些服务器对 example.com 负责。如果这些域名服务器就位于它们所服务的区域内,比如 ns1.example.com,父区域还会把它们的地址保存为胶水记录,否则解析器就找不到它们。

委派常见的出错方式有两种。残缺委派(lame delegation)是指父区域指向一台已不再服务该区域的服务器,通常发生在更换服务商之后,会导致部分用户超时或收到 SERVFAIL。另一种是父区域中的 NS 记录与区域内部的 NS 记录不一致,这会让行为取决于解析器碰巧缓存了哪一组。

传输与隐私

大多数 DNS 流量走的是 53 端口上的 UDP。装不下的应答会设置截断(truncation)标志,客户端随后通过 TCP 重试,所以 TCP 53 端口也必须开放。自 DNS Flag Day 2020 以来,主流 DNS 软件默认使用 1,232 字节的 EDNS 缓冲区大小,以避免 IP 分片,这使得 DNSSEC 签名记录这类大应答更常回退到 TCP。

传统 DNS 是不加密的。DNS over TLS(853 端口)、DNS over HTTPS 和 DNS over QUIC 加密的是存根解析器与递归解析器之间的那一段;从解析器到根、TLD 和权威服务器的各段大多仍是明文。

DNSSEC 解决的是另一个问题:真实性,而不是隐私。每个区域对自己的记录签名,父区域为子区域的密钥背书,一直延伸到执行验证的解析器所信任的根密钥。2026 年 10 月 11 日,根区域完成了轮换,启用新的密钥签名密钥 KSK-2024。没有更新信任锚的验证型解析器,会在每次查询时都以 SERVFAIL 失败。

查询失败时

症状 常见原因 第一步检查
NXDOMAIN 名称不存在、拼写错误,或缓存了否定应答 dig name @authoritative-server,然后看 SOA 的否定 TTL
SERVFAIL DNSSEC 验证失败、残缺委派,或权威服务器不可达 dig +dnssec name、dig +trace name
超时 防火墙拦截了 UDP 或 TCP 53,解析器过载 用 @1.1.1.1 直接查询另一个解析器
旧地址 某个缓存仍保存着之前的记录 查看该解析器 dig 应答中剩余的 TTL

用 dig @ns1.example.net app.example.com 直接询问权威服务器,能告诉你真实情况是什么;询问解析器,则能告诉你用户看到的是什么。

DNS 解析示意图

一台笔记本电脑向递归解析器发出查询。解析器按编号步骤依次询问根服务器、com TLD 服务器和 example.com 的权威服务器,得到两次引荐和一条 TTL 为 300 秒的 A 记录,然后把它返回给笔记本电脑。

8 个组件 · 9 个连接

在 Archboard 中打开
图表内容
  • Laptop + stub resolver
  • Recursive resolver + cache
  • DNS hierarchy
  • Root servers ( . )
  • TLD servers (com.)
  • Authoritative: example.com
  • app.example.com 203.0.113.10
  • 1. A? app.example.com
  • 8. 203.0.113.10, TTL 300
  • 2. Who serves com.?
  • 3. Referral: com. NS + glue
  • 4. Who serves example.com?
  • 5. Referral: example.com NS
  • 6. A? app.example.com
  • 7. A 203.0.113.10, TTL 300
  • 9. HTTPS to 203.0.113.10
对 app.example.com 的一次查询。递归解析器从根服务器一路查到权威服务器,把每个应答按其 TTL 缓存起来;下一个客户端无需解析器再向外查询,就能拿到地址。

这张图的读法如下:

  • 从笔记本电脑开始看。 它的存根解析器向解析器发出一次递归查询(第 1 步),并收到一次应答(第 8 步)。
  • 逐级查询由解析器完成。 第 2 到第 7 步是迭代查询:根服务器和 com 服务器返回引荐,example.com 的权威服务器返回记录。
  • TTL 标在应答上。 A 记录随 300 秒的 TTL 一起返回,这就是解析器无需再次询问而重复使用它的时长。
  • 框架把你不负责运营的层级归为一组,权威服务器除外,它属于你或你的 DNS 服务商。
  • Markdown 块列出了各层缓存,以及决定变更多快到达用户的 TTL。

画出能回答实际问题的 DNS 图

  • 给步骤编号。 DNS 问题关乎顺序:谁询问谁,以及什么时候由缓存代为应答。
  • 区分递归流量和迭代流量。 客户端只发一次查询,解析器则发多次。如果两者看起来一样,这张图就掩盖了最重要的概念。
  • 把 TTL 写在应答上。 它们比一段文字更能解释传播。
  • 标明归属。 标出哪些服务器由你掌控。出事时,这决定了你该联系谁。
  • 把记录变更单独画成一张图。 一条包含调低 TTL、切换和调回 TTL 的迁移时间线,比在解析图上加注释更清楚。

如果消息的顺序才是重点,也可以使用时序图,把解析器和每台服务器画成生命线。至于物理层面,也就是解析器在你网络中的位置,请参阅网络拓扑图指南。

在 Archboard 中构建

  1. 使用 Google 或 GitHub 登录,并新建一张图。
  2. 添加一个网络节点包中的 设备 节点表示笔记本电脑,再添加一个 DNS 节点表示递归解析器。
  3. 添加一个以 DNS 层级命名的基础 框架,在其中再放三个 DNS 节点:根服务器、com TLD 和 example.com 的权威服务器。
  4. 添加一个网络节点包中的 服务器 节点表示 app.example.com,即浏览器在解析完成后连接的主机。
  5. 按顺序画出连线并为标签编号:先是客户端的查询和应答,然后是解析器与每台服务器之间的查询和应答。把 TTL 写在最后的应答上。
  6. 添加一个基础节点包中的 Markdown 块,写上各层缓存和 TTL 规则。

这个示例共用 8 个图表节点,在 Free 套餐的限制之内。

常见问题

DNS 传播需要多长时间? 对每个缓存了旧记录的解析器而言,最长为旧记录的 TTL。并没有推送,只是缓存过期。更换域名服务器需要更久,因为父区域的 NS 记录有自己的 TTL,在 com 中为两天。

递归 DNS 服务器和权威 DNS 服务器有什么区别? 递归解析器代表客户端查找答案并缓存。权威服务器保存某个区域的记录,并且只为该区域作答。

修改记录后为什么还能看到旧 IP 地址? 你和权威服务器之间的某个缓存仍保存着旧记录:可能是浏览器、操作系统或解析器。直接查询权威服务器确认变更已生效,然后等待 TTL 过期。

TTL 设得很低会有问题吗? 这会让你的 DNS 服务商收到更多查询,用户也要做更多完整解析,从而在缓存未命中时增加延迟。对可能需要故障切换的记录使用低 TTL,对稳定的记录使用较长的 TTL。

DNS 流量是加密的吗? 默认不是。DNS over TLS、HTTPS 或 QUIC 会加密你的设备与解析器之间的那一段。DNSSEC 添加签名来证明记录是真实的,但并不加密任何内容。

免费开始 — 1 个席位,无需信用卡。

相关文章

← 返回博客

一分钟打开画布

使用 Google 或 GitHub 登录。单席位免费,团队加入后再升级。