深入浅出 DNS 解析
DNS 如何工作?更新网站的 DNS 记录的时候发生了什么?更新后必须等待 48 小时才能生效吗?为什么有人看到的是新 IP,有人看到的是旧 IP?
DNS 分类
我们知道,DNS 服务器有两种:权威服务器(authoritative)和递归服务器(recursive)
权威 DNS 服务器(也称为名称服务器,NS,nameserver)具有其所负责的每个域的 IP 地址数据库。
例如,github.com 的权威 DNS 服务器是 NS-421.awsdNS-52.com
递归 DNS 服务器,本身并不知道谁拥有什么 IP 地址。它们通过询问正确的权威 DNS 服务器,找出域名的 IP 地址,然后缓存这个 IP 地址,以备再次询问。8.8.8.8 是一个递归 DNS 服务器。
当人们访问你的网站时,他们可能会向递归 DNS 服务器进行 DNS 查询。那么,递归 DNS 服务器是如何工作的呢?
递归 DNS 服务器如何工作
以 8.8.8.8 为例,如果我们向其请求 github.com 的 IP 地址(A 记录),如果它存在缓存,那么就直接返回缓存结果。然而,缓存是有期限的,如果所有缓存都过期了呢?那么情况是这样的:
-
递归服务器内部硬编码(hardcoded)有根
DNS服务器.的IP地址(参见 [2][3]),选择一个根DNS服务器,例如198.41.0.4 -
询问根
DNS服务器有关com.的NS此步可以使用如下方法模拟:
$ dig @198.41.0.4 github.com ... com. 172800 IN NS a.gtld-servers.net. ... a.gtld-servers.net. 172800 IN A 192.5.6.30 ...可以看到,这里我们得到一个
com.的权威 NSa.gtld-servers.net.及其 IP 地址192.5.6.30注意实际上,99.99% 的情况下,此步我们就将得到github.com的 A 记录,但为了展示完整DNS解析进程,假设这里我们没有得到。 -
询问该权威
NS有关github.com的NS$ dig @192.5.6.30 github.com ... github.com. 172800 IN NS NS-421.awsdNS-52.com. NS-421.awsdNS-52.com. 172800 IN A 205.251.193.165 ...这里,我们得到的
github.com.NSNS-421.awsdNS-52.com.及其IP地址205.251.193.165 -
询问该
NS有关github.com的 A 记录$ dig @205.251.193.165 github.com github.com. 60 IN A 140.82.112.4至此,在假设没有缓存的情况下,我们通过完整的流程(实际上绝大多数情况不需要完整进行)获得了
github.com的IP地址。
此外,使用 $ dig @8.8.8.8 +trace github.com 可以一次性显示上述所有步骤。
更新 DNS 记录
更新 DNS 记录时,有两种情况:
-
保持相同的 NS
-
变更 NS
首先谈谈生存时间(TTLs,time to live)
上面已经说到,DNS 服务器一般存有缓存,而控制缓存是否过期的参数就是 TTL。
我们假设得到一个查询结果:
$ dig @205.251.193.165 github.com
github.com. 60 IN A 140.82.112.4
这里的 60(秒)即表示 TTL,这是一个很短的 TTL。理论上,如果每个用户都遵循 DNS 标准,那么 github.com 在更改了 IP 地址后,每个用户都应该在 60 秒内得到这个新的地址。但实际上呢?
更新同一 NS 上的 DNS 记录
假设我们已经在域名商处更新了新的 DNS 记录 test.jvNS.ca–>1.2.3.4,试着查询:
$ dig @8.8.8.8 test.jvNS.ca
test.jvNS.ca. 299 IN A 1.2.3.4
如果此前没有设置过 DNS 记录,因为没有缓存,所以立刻生效了。这里可以看到 TTL 是 299。那么,修改 IP 为 5.6.7.8 呢。
$ dig @8.8.8.8 test.jvNS.ca
test.jvNS.ca. 144 IN A 1.2.3.4
可以看到,IP 并没有发生改变且 TTL 表示缓存还将存在 144 秒。而且,多次查询,你可能会发现,有时候可以得到新的 IP,但有的时候又是旧的 IP。
这里是因为像 8.8.8.8 这样的 DNS 服务器采用了负载均衡,每次查询可能被分配到不同的后端服务器,而他们的缓存不尽相同。
等待 5 分钟后,所有的缓存都更新了,再次查询,将会始终返回新 IP。
TTL 并非总是可靠
与大多数互联网协议一样,并不是所有的终端都服从 DNS 规范(包括 8.8.8.8 这样的大型 DNS 也不尊重 TTL)。一些 ISP 的 DNS 服务器会将缓存记录的时间比 TTL 规定的时间长,比如可能是 2 天而不是 5 分钟。而且人们总是可以在他们的 /etc/hosts 中硬编码旧的 IP 地址。
此外,应用程序(例如浏览器)都内置了自己的 DNS 缓存,或者本地网关也存在缓存。
这也是为什么,即便正确地设置了对应的 TTL(大部分 DNS 将会在短时间内更新缓存),有些 DNS 服务器仍然需要更长时间生效,这也导致我们的查询也并不总是会得到新的 IP 地址。
连同 NS 一起更新
假设此前的 NS 为 dNS1.p01.NSone.net,现在我们把他修改为谷歌的 NSNS-cloud-b1.googledomaiNS.com。
通常,当你修改完成后,你的域名商会提示你:“修改将在 48 小时内生效”。
然后设置一个新的 A 记录指向 1.2.3.4
dig 看看:
$ dig @8.8.8.8 examplecat.com
examplecat.com. 17 IN A 104.248.50.87
8.8.8.8 没有变化,询问别的 DNS:
$ dig @1.1.1.1 examplecat.com
examplecat.com. 299 IN A 1.2.3.4
1.1.1.1 更新了。
造成这样不同结果的原因,可能是此前并没有人询问过 1.1.1.1,所以他没有缓存,能立刻得到新的 IP。
而如果我们向新的 NS 查询,肯定会得到新的 IP 记录:
$ dig @NS-cloud-b1.googledomaiNS.com examplecat.com
examplecat.com. 300 IN A 1.2.3.4
NS 的 TTL 要长很多
域名商提示:“修改将在 48 小时内生效” 的原因是 NS 记录(告诉递归 NS 应该向哪个 NS 查询)的 TTL 要长的多。
回到上一节中,我们的查询结果显示:
$ dig @192.5.6.30 github.com
...
github.com. 172800 IN NS NS-421.awsdNS-52.com.
NS-421.awsdNS-52.com. 172800 IN A 205.251.193.165
...
172800 秒是 48 小时!这就是为什么更改 NS 后需要更长的时间来生效。
NS 如何得到更新?
更新 NS 后,我们向根服务器查询的话就会到得到这样的结果:
$ dig NS @j.gtld-servers.net examplecat.com
examplecat.com. 172800 IN NS NS-cloud-b1.googledomaiNS.com
你可能会疑惑,新的 NS 记录是如何在根服务器处更新的呢?是因为当你在域名商那里更改你域名的 NS 后,他们会负责将这个给更改告知根服务器。
通常这个更新将在几分钟内就生效,但是对于其他一些顶级域名(TLD)(非.com)可能速度稍微慢一些。
总结
本文展示了 DNS 的解析过程以及我们更新 DNS 记录时发送了什么,希望有助于你理解这一过程。