你给博客换了服务器,在管理后台把域名指向新 IP。自己刷新页面,看到的却还是旧网站;朋友那边已经正常,手机切到移动网络后也正常。
为什么同一个域名,会在不同设备上得到不同结果?
要解释这件事,不能只把 DNS 理解成一本“域名对应 IP 的电话簿”。它是一套分层管理、分散查询、允许缓存的系统。下面跟着一次查询走完,再回头看博客换服务器的问题。
浏览器准备访问:
https://www.example.com/articles/network需要查询地址的是其中的www.example.com。https决定如何访问,/articles/network表示网站里的资源路径,都不属于这次地址查询的域名。
DNS 通常也不知道你想读哪篇文章。它先帮助浏览器找到可以连接的地址,之后才轮到 TCP、TLS 和 HTTP。
设备发起网络查询前,可能已经在浏览器或系统缓存里找到可用结果。不同系统、浏览器的处理细节不完全相同;下面先假设缓存里没有答案,需要向外查询。
设备首先联系的,通常是递归解析器。你在网络配置里看到的“DNS 服务器”,往往就是它的地址,也可能是负责转发查询的家用路由器。这个地址可以由 DHCP 提供,或由用户、系统、浏览器另行配置。
所以,电脑不必先查域名,才能找到第一个 DNS 服务器:它通常已经知道可以把查询发往哪个 IP。
你可以把这次请求读成:
请帮我查出
www.example.com的 IPv4 地址,查完把结果交给我。
递归解析器收到请求后,也会先查自己的缓存。它服务的可能不止你一台设备,别的用户刚查过相同记录,你就可能直接用上缓存结果。
假设它也没有相关缓存,才需要沿着 DNS 的层级继续寻找。
域名从右往左看,能看出管理层级:
www.example.com. │ └─ 根:最后这个点平时常省略 └─── com:顶级域 example.com:一个具体域名 www.example.com:这个域名下的名称这里要分清两个角色:递归解析器负责替你查;权威 DNS 服务器负责提供自己管理范围内的正式记录。
在这个简化例子里,递归解析器会经历三轮问路:
- 问根服务器。根服务器给出负责
.com的服务器线索。 - 问
.com的服务器。它给出负责example.com的权威服务器线索。 - 问
example.com的权威服务器。如果www.example.com的地址记录由它管理,它就返回相应记录。
注意,是递归解析器拿到线索后继续发问。根服务器一般不会替你一路查到网站,再把最终 IP 送回来。
设备向递归解析器提出的是“请帮我查到结果”的请求;解析器沿途进行的查询,则可能得到“去问这些服务器”的转介。课本里说的递归查询与迭代查询,可以先从这个区别理解。DNS 的基本查询模型见 RFC 1034。
实际查询不一定每次走完三层。只要缓存里还留着可用的答案或中途线索,解析器就能少走几步。域名也可能继续委派给其他权威服务器,这里先保留最常见的主干。
查到的“答案”,究竟长什么样?
DNS 保存的是一条条有类型的记录。你问某个名称的 IPv4 地址,通常查询A 记录;问 IPv6 地址,则查询AAAA 记录。同一个名称可以有不同类型的记录,它们回答不同问题:
| 记录类型 | 表达的内容 |
|---|---|
| A | 这个名称对应的 IPv4 地址 |
| AAAA | 这个名称对应的 IPv6 地址 |
| CNAME | 这个名称是另一个名称的别名 |
| NS | 哪些服务器负责相应 DNS 区域 |
| MX | 这个域名接收邮件时使用哪些邮件服务器 |
| TXT | 文本信息,常用于域名验证、邮件策略等 |
因此,“查不到 A 记录”不等于“域名不存在”。它可能有其他记录,只是没有你正在查询的这一种。
CNAME 也值得单独说一下。假设博客配置成:
blog.example.com → site.hosting.example这条别名记录本身没有给出 IP。解析过程还需要继续查目标名称的地址。浏览器的网址也不会因为收到 CNAME,就自动变成右边那个名字;DNS 别名与网页跳转是两回事。
一个名称还可能返回多个地址。大型网站可以根据解析器位置、服务部署和调度策略给出不同结果。两个人查到的 IP 不同,单凭这一点还不能断定谁的 DNS 出错了。
查完之后,为什么要缓存?
如果每次打开博客,都从根服务器开始问一遍,访问会变慢,DNS 系统也会承受大量重复查询。于是,解析器会把可缓存的记录暂时保留下来。
记录中的TTL用来告诉缓存:这份记录通常可以保存多久,单位是秒。这里的 TTL 与第五篇 IP 数据包中的 TTL 含义不同:DNS TTL 管缓存时间,IP TTL 限制数据包的转发寿命。相关定义见 DNS 术语规范 RFC 9499。
假设博客原来的记录是:
blog.example.com → 旧服务器地址 TTL = 3600 秒某个解析器在 10:00 缓存了它。你在 10:10 把权威服务器上的记录改成新地址,这个解析器并不一定立刻得知变化:它手里的旧记录仍可能在剩余有效时间内被使用。
另一个解析器恰好没有旧缓存,10:11 去查询时,就可能拿到新地址。于是,同一个博客出现了“我这里还是旧的,他那里已经新的”。
这也说明,域名修改后所谓的“生效”,通常不能理解为有一条更新消息正在逐台推送给全世界。权威记录更新了,各处旧缓存还需要陆续到期。
准备迁移博客时,如果希望缩短切换期间旧缓存的影响,可以提前降低相关记录的 TTL,并等原来的较长缓存周期过去,再修改地址。切换当天才降低 TTL,不会自动缩短别人已经缓存的旧记录剩余时间。
甚至“这个名字不存在”的结果也可以被缓存。刚创建一个此前查不到的名称时,短时间内仍有人得到不存在的回答,可能与这种否定缓存有关。这一机制由 RFC 2308 说明。
现在可以在自己的电脑上看一次真实查询了。Windows 打开命令提示符,输入:
nslookup -type=A example.com先观察输出的两部分。开头的Server、Address通常表示你正在询问的 DNS 服务器;后面的名称和地址,才是被查询域名的结果。第一次使用这个命令,很容易把两者看反。
如果看到“非权威应答”,通常表示回答你的这台服务器不是该名称的权威来源。它可能从缓存中回答,也可能刚替你完成查询。这几个字本身不表示答案不可信。
再分别运行:
nslookup -type=AAAA example.com nslookup -type=NS example.com第一条查询 IPv6 地址,第二条查看这个域名的 NS 记录。记录内容可能变化,以你实际看到的结果为准。
如果想找 TTL,可以查看更详细的输出:
nslookup -debug -type=A example.com找到相应回答记录里的ttl。连续查询时,你可能看到它下降,也可能由于缓存刷新、不同后端等原因看到不同变化;不必要求每次结果完全一样。
遇到失败时,先分清失败的种类:
| 结果 | 通常说明什么 |
|---|---|
| NXDOMAIN/不存在的域 | DNS 回答这个名称不存在 |
| SERVFAIL | 解析过程失败,原因可能在服务器、验证或其他环节 |
| 超时 | 在等待期限内没有收到可用回应 |
| 查询成功但没有该类型记录 | 名称可能存在,只是没有这类记录 |
不要把后三种情况一律解释为“域名写错了”。命令用法及错误说明可参考微软的 nslookup 文档。
还有一个排查时很有用的边界:nslookup成功,不保证浏览器正在使用同一个查询结果。浏览器可能有自己的缓存,也可能启用了独立的加密 DNS 服务。浏览器仍打不开网站时,需要确认它实际使用的解析方式,而不是只反复运行同一条命令。
即便浏览器拿到了正确 IP,后面还有连接、TLS 和 HTTP 等步骤。DNS 完成的是地址查询,不会替网站检查证书是否有效、服务是否启动、文章是否存在。
今天的练习做到这里,可以在纸上留下四项:你询问的 DNS 服务器、查询的名称、记录类型、返回结果。下次博客换服务器时,再分别比较权威记录和递归查询结果,你就有了判断旧地址从哪里来的依据。
下一篇,我们终于可以读一读浏览器与网站真正交换的内容:一条 HTTP 请求里写了什么,服务器又怎样用状态码、响应头和正文回答它。