2016年10月21日,美国东海岸发生了一次大规模互联网中断。Twitter、Netflix、Reddit、Spotify等众多知名网站同时无法访问。数百万用户盯着浏览器上的"DNS_PROBE_FINISHED_NXDOMAIN"错误发呆。问题根源是一家DNS服务提供商遭到了DDoS攻击——DNS解析服务瘫痪,整个互联网仿佛被切断了电话线。

这不是孤例。2023年,全球DNS平均响应时间为263毫秒,但自建DNS解决方案比全球平均水平慢35%。更糟糕的是,很多开发者对DNS的理解停留在"域名解析成IP地址"这个表面层面。当遇到DNS问题时,往往只能等待"传播完成",却不知道到底在等什么。

一次DNS查询的完整旅程:从浏览器到权威服务器

当你在浏览器输入www.example.com并按下回车时,一系列复杂的查询过程悄然启动。这不是简单的"查表",而是一场跨越全球的接力赛。

第一站:本地缓存层

浏览器首先检查自己的DNS缓存。Chrome可以在chrome://net-internals/#dns查看缓存状态,Chrome会缓存DNS记录约1分钟(具体时间取决于记录的TTL)。如果命中,整个解析过程就此结束,耗时接近零。

如果浏览器缓存未命中,查询传递给操作系统。操作系统的"stub resolver"会检查自己的缓存。在Windows上可以用ipconfig /displaydns查看,Linux则查看/etc/hosts和systemd-resolved缓存。

如果本地缓存都未命中,查询离开你的设备,进入互联网。

第二站:递归解析器

操作系统配置的DNS服务器(通常由DHCP自动分配,可能是ISP的DNS或公共DNS如8.8.8.8)收到查询。这个服务器被称为递归解析器(Recursive Resolver),它是DNS查询的"大管家"。

递归解析器首先检查自己的缓存。如果缓存中有答案,直接返回——这是最常见的"快速解析"场景。根据APNIC的测量数据,超过80%的DNS查询可以被递归解析器的缓存直接响应。

如果缓存未命中,递归解析器开始一场"从根到叶"的迭代查询。

第三站:根域名服务器

递归解析器向13个根域名服务器之一发送查询。这里有个常见误解:13个根服务器不是13台机器,而是13个IP地址,每个IP地址背后是数百台服务器通过Anycast技术分布在全球。截至2024年,根服务器系统共有超过1700个实例。

根服务器不会直接返回www.example.com的IP地址——它不知道也不关心这个。它返回的是.com顶级域的权威服务器列表。

;; QUESTION SECTION:
;www.example.com.               IN      A

;; AUTHORITY SECTION:
com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
...

第四站:TLD域名服务器

递归解析器选择一个.com TLD服务器发送查询。TLD服务器同样不会返回最终答案,而是返回example.com这个域的权威服务器列表。

;; AUTHORITY SECTION:
example.com.            172800  IN      NS      ns1.example.com.
example.com.            172800  IN      NS      ns2.example.com.

第五站:权威域名服务器

递归解析器最终向example.com的权威服务器发送查询。权威服务器是最终答案的来源——它持有该域的DNS区域文件,返回真正的A记录:

;; ANSWER SECTION:
www.example.com.        86400   IN      A       93.184.216.34

整个过程涉及4类服务器的协作:递归解析器、根服务器、TLD服务器、权威服务器。在完全无缓存的情况下,一次DNS解析可能需要数十到数百毫秒,取决于网络延迟和服务器响应速度。

sequenceDiagram
    participant B as 浏览器
    participant O as OS缓存
    participant R as 递归解析器
    participant Root as 根服务器
    participant TLD as TLD服务器
    participant Auth as 权威服务器

    B->>O: 查询 www.example.com
    O-->>B: 未命中
    O->>R: 递归查询 www.example.com
    R->>R: 检查本地缓存
    R->>Root: 查询 .com 的NS
    Root-->>R: 返回 .com TLD服务器列表
    R->>TLD: 查询 example.com 的NS
    TLD-->>R: 返回 example.com 权威服务器
    R->>Auth: 查询 www.example.com 的A记录
    Auth-->>R: 返回 93.184.216.34
    R-->>O: 返回IP地址
    O-->>B: 返回IP地址

多级缓存:为什么DNS"传播"需要48小时

当你在域名服务商后台修改了DNS记录,通常会看到提示"DNS传播可能需要24-48小时"。很多人困惑:为什么修改一个记录要这么久?DNS不是实时的吗?

问题的核心在于:DNS本质上是一个分布式缓存系统,而不是一个实时数据库。

缓存的四个层级

DNS缓存存在于网络路径的多个位置:

缓存层级 位置 缓存时间 控制权
浏览器缓存 用户设备 通常1分钟 浏览器决定
OS缓存 用户设备 通常几分钟到几小时 操作系统决定
递归解析器缓存 ISP/公共DNS 遵循TTL,但可能被覆盖 ISP决定
权威服务器 DNS服务商 无缓存,返回权威答案 你控制

当你修改DNS记录时,你只更新了权威服务器上的数据。但在此之前,无数个缓存服务器可能还保存着旧记录。

TTL:被误解的"有效期"

每个DNS记录都有一个TTL(Time To Live)字段,单位是秒。TTL的本意是告诉缓存服务器:“这个记录你可以缓存这么久,过期后请重新查询”。

www.example.com.    3600    IN    A    93.184.216.34
                    ↑
                    TTL = 3600秒 = 1小时

理论上,如果TTL设置为1小时,那么修改记录后最多1小时,所有缓存都会过期并获取新值。但现实远比这复杂:

问题一:ISP可能忽略你的TTL

很多ISP的DNS服务器会自行设置最小/最大TTL,无视权威服务器返回的值。某些ISP会将所有TTL截断为固定值(如1小时或更长),或者在TTL很短时故意延长缓存时间以减少查询量。这是为什么"DNS传播"时间难以预测的主要原因。

问题二:负缓存的存在

DNS不仅缓存"存在的记录",也缓存"不存在的记录"。这叫负缓存(Negative Caching)。如果你查询了一个不存在的域名,递归解析器会缓存NXDOMAIN响应,缓存时间由SOA记录中的minimum字段决定(RFC 2308规定)。

这导致一个常见陷阱:你删除了一条记录,过了几分钟又想恢复,却发现域名仍然无法解析——因为递归解析器缓存了"该记录不存在"的负响应。

问题三:多台权威服务器的同步延迟

大多数域使用多台权威服务器(通常是2-5台)以提供冗余。当你修改记录时,主服务器立即更新,但从服务器需要通过区域传送(AXFR/IXFR)同步。这个同步过程可能需要几秒到几分钟。

为什么"传播"这个词具有误导性

“DNS传播"这个词暗示数据从源点向外扩散。但实际上,DNS没有"推送"机制——缓存服务器不会主动获取更新。

更准确的描述是缓存过期:旧记录在各个缓存服务器中过期,新的查询才会获取最新值。这个过程是被动的、分散的、不可控的。

DNS协议解析:理解报文层面的细节

要真正理解DNS,需要深入协议层面。DNS使用UDP端口53(响应超过512字节时使用TCP),报文格式在RFC 1035中定义。

DNS报文结构

+---------------------+
|        Header       |  12字节
+---------------------+
|      Question       |  查询的问题
+---------------------+
|       Answer        |  回答的资源记录
+---------------------+
|      Authority      |  权威服务器记录
+---------------------+
|      Additional     |  附加信息
+---------------------+

Header部分包含几个关键字段:

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

几个重要的标志位:

  • QR(Query/Response):0表示查询,1表示响应
  • AA(Authoritative Answer):1表示来自权威服务器
  • TC(Truncation):1表示响应被截断(超过UDP限制)
  • RD(Recursion Desired):客户端请求递归解析
  • RA(Recursion Available):服务器支持递归解析
  • RCODE(Response Code):响应状态码

DNS响应码(RCODE)

RCODE 名称 含义
0 NOERROR 成功
1 FORMERR 格式错误,服务器无法理解查询
2 SERVFAIL 服务器失败,无法处理查询
3 NXDOMAIN 域名不存在
4 NOTIMP 不支持该查询类型
5 REFUSED 拒绝查询(通常是权限问题)

使用dig命令诊断DNS

dig是最强大的DNS诊断工具(Windows用户可使用nslookup或安装BIND工具包):

# 基本查询
dig example.com

# 指定DNS服务器
dig @8.8.8.8 example.com

# 查询特定记录类型
dig example.com MX
dig example.com AAAA
dig example.com TXT

# 显示完整的DNS报文
dig +nocmd +noall +answer +additional example.com

# 追踪完整解析路径
dig +trace example.com

dig +trace会模拟递归解析器的行为,显示从根服务器开始的完整查询链路:

; <<>> DiG 9.16.1-Ubuntu <<>> +trace example.com
;; global options: +cmd
.                       518400  IN      NS      a.root-servers.net.
.                       518400  IN      NS      b.root-servers.net.
;; Received 261 bytes from 192.168.1.1#53(192.168.1.1) in 3 ms

com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
;; Received 774 bytes from 198.41.0.4#53(a.root-servers.net) in 28 ms

example.com.            172800  IN      NS      ns1.example.com.
example.com.            172800  IN      NS      ns2.example.com.
;; Received 180 bytes from 192.5.6.30#53(a.gtld-servers.net) in 45 ms

example.com.            86400   IN      A       93.184.216.34
;; Received 62 bytes from 199.43.135.53#53(ns1.example.com) in 12 ms

常见DNS错误诊断:SERVFAIL、NXDOMAIN、REFUSED

SERVFAIL:服务器遇到了问题

SERVFAIL是最令人头疼的错误,因为它是一个"通用失败"响应——服务器告诉客户端"我搞砸了,但我不告诉你具体原因”。

常见原因:

  1. DNSSEC验证失败:如果域名启用了DNSSEC,但签名过期或配置错误,验证型递归解析器会返回SERVFAIL
  2. 权威服务器无响应:递归解析器无法联系到任何权威服务器
  3. 区域文件损坏:权威服务器的区域文件存在语法错误
  4. 网络连接问题:递归解析器与权威服务器之间的网络不通

诊断步骤:

# 使用不同的递归解析器测试
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com

# 禁用DNSSEC验证测试
dig @8.8.8.8 +cd example.com  # CD = Checking Disabled

# 直接查询权威服务器
dig @ns1.example.com example.com

NXDOMAIN:域名不存在

NXDOMAIN表示查询的域名确实不存在,但有时这是一个"假阴性":

# 检查是否是负缓存导致的问题
# 清除本地缓存(不同系统命令不同)

# Windows
ipconfig /flushdns

# Linux (systemd-resolved)
sudo systemd-resolve --flush-caches

# macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

REFUSED:拒绝查询

REFUSED通常意味着你查询了不该查询的内容:

  • 递归解析器配置为拒绝来自某些IP的查询
  • 权威服务器拒绝为其不负责的域提供答案
  • 尝试进行未被授权的区域传送(AXFR)

DNS安全威胁:污染、劫持与防护

DNS设计于1980年代,安全并非首要考虑。这导致了几种主要的攻击方式。

DNS缓存投毒(DNS Cache Poisoning)

2008年,安全研究员Dan Kaminsky发现了一个严重的DNS漏洞:攻击者可以伪造DNS响应,向递归解析器的缓存中注入虚假记录。

攻击原理:DNS查询使用UDP,没有握手验证。攻击者如果能抢在真实响应之前发送伪造响应,就能污染缓存。

受害者查询: www.bank.com
攻击者伪造响应: www.bank.com -> 恶意IP
递归解析器缓存该虚假记录
所有后续用户被导向恶意服务器

现代DNS服务器已通过源端口随机化和事务ID随机化大大增加了攻击难度。Kaminsky漏洞披露后,DNS软件迅速更新,补丁普及率很高。

DNS劫持(DNS Hijacking)

DNS劫持是更高层次的攻击——不是欺骗缓存,而是直接控制DNS服务器。攻击者可能:

  • 入侵域名注册商账户,修改NS记录
  • 入侵DNS服务商,修改区域文件
  • 利用社会工程学欺骗注册商转移域名

2019年,多起针对中东政府的DNS劫持攻击被发现。攻击者将政府网站的DNS记录指向攻击者控制的服务器。

DNS污染(DNS Spoofing)

在某些网络环境下,DNS查询会被中间设备拦截并返回虚假响应。这与缓存投毒不同——污染发生在传输路径上,而不是缓存层面。

中国的"防火墙"使用DNS污染技术:当检测到对特定域名的查询时,无论真实IP是什么,都返回一个虚假IP。这个虚假IP通常指向一个不存在的服务器,导致连接失败。

防护措施

1. 使用DNS over HTTPS (DoH) 或 DNS over TLS (DoT)

这两个协议加密DNS查询,防止中间人窥探和篡改:

协议 端口 特点
DoT 853 专用端口,易于识别和封锁
DoH 443 混在HTTPS流量中,难以区分

DoH在2018年由RFC 8484标准化,将DNS查询封装在HTTP/2中。主流浏览器(Chrome、Firefox)已支持DoH。

2. 启用DNSSEC

DNSSEC通过数字签名验证DNS响应的真实性。它不加密查询,但能检测篡改。

DNSSEC使用两种密钥:

  • ZSK(Zone Signing Key):签名区域内的记录
  • KSK(Key Signing Key):签名ZSK,建立信任链

信任链从根区域开始,逐级向下验证。每个父区域通过DS(Delegation Signer)记录认证子区域的KSK。

graph TD
    A[根区域 KSK] -->|签名| B[.com DS记录]
    B -->|认证| C[example.com KSK]
    C -->|签名| D[example.com ZSK]
    D -->|签名| E[www.example.com A记录]

3. 使用可信的DNS解析器

公共DNS服务如Google DNS (8.8.8.8)、Cloudflare DNS (1.1.1.1) 通常比ISP的DNS更安全、更快。它们支持DNSSEC验证、不进行DNS劫持、有严格的安全策略。

现代DNS技术:性能与安全的演进

Anycast:让全球DNS响应更快

DNS根服务器和大型DNS服务商都使用Anycast技术。简单说,Anycast让多个服务器共享同一个IP地址,BGP路由会自动将请求导向"最近"的服务器。

这意味着:

  • 用户查询8.8.8.8,实际可能连接到新加坡的Google DNS节点
  • 另一个用户查询同样的地址,可能连接到美国的节点
  • 请求永远不会跨越半个地球

Anycast不仅提升性能,还提供DDoS防护能力:攻击流量会被分散到全球多个节点。

CNAME扁平化:解决根域名的CNAME限制

RFC 1912规定:CNAME记录不能与其他记录共存。问题在于,域名根(如example.com)必须有SOA和NS记录,因此不能使用CNAME。

这导致一个常见困境:你想把根域名指向某个CDN或云服务,但CDN只提供CNAME。

解决方案是CNAME扁平化(CNAME Flattening):DNS服务商在权威层面解析CNAME链,最终返回A记录而不是CNAME。对查询者来说,收到的是直接的IP地址,符合RFC规范。

EDNS:突破512字节限制

原始DNS协议限制UDP响应最大512字节。随着DNSSEC(签名数据较大)和IPv6(AAAA记录更长)的普及,这个限制成为问题。

EDNS(Extension Mechanisms for DNS,RFC 6891)允许:

  • 通告更大的UDP包大小(通常4096字节)
  • 添加扩展字段(如ECS,用于传递客户端子网信息)

如果响应仍然超过限制,TC(Truncation)标志会被设置,客户端需要改用TCP重新查询。

性能优化实践:从TTL设置到预解析

TTL设置策略

TTL是性能与时效性的权衡:

场景 建议TTL 原因
稳定的生产环境 3600-86400 减少查询,提升性能
计划变更前 300-600 缩短传播时间
负载均衡/故障切换 30-300 快速切换后端
开发/测试环境 60-300 频繁变更

最佳实践:

  1. 计划变更前24-48小时,先将TTL降低
  2. 变更完成后,观察一段时间,再将TTL恢复

DNS预解析(dns-prefetch)

浏览器支持DNS预解析,可以在用户点击链接之前就完成DNS查询:

<!-- 预解析第三方域名 -->
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="dns-prefetch" href="//api.example.com">

预解析只进行DNS查询,不建立连接。更进一步的preconnect会同时完成DNS、TCP和TLS握手:

<link rel="preconnect" href="https://cdn.example.com">

监控DNS性能

定期检测DNS解析时间,设置告警:

# 使用dig测量查询时间
dig +stats example.com | grep "Query time"

# 输出示例
;; Query time: 12 msec

对于关键业务,建议:

  • 使用多个DNS服务商实现冗余
  • 监控权威服务器的可用性
  • 跟踪DNS解析延迟趋势

参考资料

  1. RFC 1034 - Domain Names: Concepts and Facilities
  2. RFC 1035 - Domain Names: Implementation and Specification
  3. RFC 2308 - Negative Caching of DNS Queries
  4. RFC 6891 - Extension Mechanisms for DNS (EDNS(0))
  5. RFC 8484 - DNS Queries over HTTPS (DoH)
  6. APNIC Labs - DNS nameservers: Service performance and resilience (2025)
  7. Cloudflare Learning Center - DNS Server Types
  8. DigiCert - DNSSEC Validation Chain of Trust
  9. Verisign - The Domain Name System Briefing
  10. ICANN - Root Server System Overview
  11. DNS-OARC - DNS Reply Size Test Server
  12. Google Public DNS - Troubleshooting Guide
  13. DNSPerf - DNS Performance Analytics and Comparison