当你更新你的 DNS 时会发生什么
关于 DNS 的基础知识,可参考阮大佬的: DNS 原理入门 。
以下为正文:
我看到过许多人对更新他们站点的 DNS 记录以改变 IP 地址而感到困惑。为什么这么慢?你真的会花费2天的时间等待所有的数据更新吗?为什么有的人会看到新的 IP 而有些人会看到旧的 IP?到底发生了什么?
所以我想快速探索一下当你更新 DNS 时幕后所发生的一切。
DNS 如何工作:递归解析器 vs 权威域名服务器
首先,我们需要了解一点关于 DNS 的知识。DNS 服务器有两种:权威域名服务器(authoritative) 和 递归解析器(recursive)。
权威域名 DNS 服务器(也叫根域名服务器)有一个其所负责域的 IP 地址数据库。比如,目前 github.com 的权威域名服务器是 ns-421.awsdns-52.com。你可以获取 github.com 的 IP 地址像这样:
$ dig @ns-421.awsdns-52.com github.com
递归 DNS 解析器本身并不知道某一域名对应什么样的地址。它们通过询问正确的权威域名 DNS 服务器来获取对应的 IP 地址,接下来缓存这个 IP 地址,以便它们再次访问。8.8.8.8 是一个递归解析器。
当人们访问你的网站,他们可能会在递归解析器上查询。所以它是怎么工作的?一起来看!
递归 DNS 解析器如何查询 github.com?
可以通过一个例子来了解当你访问 github.com 的 IP 地址(A 记录)时递归解析器(比如8.8.8.8)做了什么。首先,如果它已经缓存了这些数据,那么将会直接使用缓存中的数据。但是如果所有的缓存都失效了该怎么办?它会做如下工作:
-
它的源代码中有根 DNS 服务器的 IP 地址。你可以参阅 [unbound’s source code here](unbound’s source code here) 。假如从
198.41.0.4
开始。下面有一些硬编码 IP 地址的官方来源: official source ,也称为『根提示文件』。 -
询问根域名服务器中的
github.com
。我们可以大致地重现使用
dig
时发生了什么,告诉了我们一个新的权威域名服务器,一个 IP 地址为192.5.6.30
的.com
域名服务器。$ 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 ...
DNS 响应的细节要复杂一些,其中一个权限部分包含一些 NS(name server) 记录,另外一个部分包含 A 记录,因此你无需通过额外的查找就可以得到 IP 地址。
(在实际中,99.99%的情况下它已经缓存了
.com
名称服务器中的内容,但是我们假装我们真的是从零开始) -
查询
.com
名称服务器中关于github.com
的信息。$ 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 ...
我们有一个新的 IP 地址需要查询!这是
github.com
的名称服务器。 -
在
github.com
名称服务器中查找关于github.com
的信息。就快要结束了!
$ dig @205.251.193.165 github.com github.com. 60 IN A 140.82.112.4
成功了!我们得到了
github.com
的A
记录!现在递归域名服务器取到了github.com
的 IP 地址,并将其返回给了你。它可以仅通过硬编码几个 IP 地址(即根域名服务器)来实现所有的这些工作。
如何查看所有的递归 DNS 服务器的流程:dig +trace
当我想要了解一个递归服务器在解析一个域名时会做什么,我会运行:
$ dig @8.8.8.8 +trace github.com
它会打印出请求的所有 DNS 记录(从根 DNS 服务器开始,会经过我们刚刚探讨过的4步)。
让我们来更新一些 DNS 记录
现在我们知道了 DNS 基本的工作流程,让我们更新一些 DNS 记录,看看会发生什么。
当你更新你的 DNS 记录时,主要有两个选择:
- 不修改名称服务器
- 修改名称服务器
谈谈 TTLs (time to live)
我们忘记了一些重要的事情!TTLs!你还记得前面说过的递归 DNS 服务器将缓存记录直到这些记录过期吗?服务器决定一个记录是否过期应该去查看它的 TTL 或者”生存时间“。
下面的例子中,github 名称服务器为 DNS 记录返回的 A 记录的 TTL 是60,意味着 60 秒:
$ dig @205.251.193.165 github.com
github.com. 60 IN A 140.82.112.4
这是一个非常短的 TTL,从理论上讲,如果每个人的 DNS 实现都遵循 DNS 标准,那么意味着如果 Github 决定改变 github.com
的 IP 地址,每个人都应该在 60 秒内得到新的 IP 地址。让我们来看看实际情况如何。
选择1 :更新同一名称服务器上的一条 DNS 记录
首先,我更新了我的名称服务器(Cloudflare)中的一条新 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
紧接着就起作用了!根本不用等待,因为之前没有缓存过 test.jvns.ca
。但是新纪录的缓存时间大约为5分钟(299秒)。
如果尝试更改这个 IP 会发生什么呢?我将 IP 地址修改为 5.6.7.8
,然后执行相同的 DNS 查询命令:
$ dig @8.8.8.8 test.jvns.ca
test.jvns.ca. 144 IN A 1.2.3.4
看起来 DNS 仍旧缓存了144秒的 1.2.3.4
。有趣的是,如果我多次查询 8.8.8.8
将会得到不一样的结果:有时候返回了新的 IP ,有时候是旧的 IP,我猜测 8.8.8.8 事实上负载平衡到不同的后端,每个后端服务器都有自己的缓存。
等待了5分钟后,所有的 8.8.8.8
都返回了刚刚新缓存的 5.6.7.8
IP 记录。Awesome,这实在是太快了!
你不能一直依赖 TTL
与大多数 Internet 协议一样,并非所有的协议都遵守 DNS 规范。一些 ISP DNS 服务器缓存的时间超过了 TTL 规定的时间,比如两天而不是5分钟。人们总是可以在他们的 /etc/hosts 中硬编码旧的 IP 地址。
在实际使用中我希望我用 5 分钟的 TTL 更新 DNS 记录时,大部分客户端会快速迁移到新的 IP(比如在15分钟内),然后剩余的客户端会在接下来的几天内陆续更新到新的 IP。
选择 2:更新你的名称服务器
刚刚我们了解了,当你没有改变你的名称服务器时更新了一条 IP 地址,许多 DNS 服务器将很快更新到新的 IP 地址。但是当你更新你的名称服务器时会发生什么?让我们来试试!
我不想更新我博客的名称服务器,所以我使用我的另一个域名,并在 HTTP zine 示例中使用了它: examplecat.com
。
之前我的名称服务器是 dns1.p01.nsone.net。我决定换成谷歌的名称服务器—— ns-cloud-b1.googledomains.com
等。
当我做了改变,我的域名注册商有点不高兴地弹出消息——”examplecat.com 已更改,将在48小时内生效“。接下来我为域名设置了一个新的 A 记录,指向 1.2.3.4
。
好的,让我们看看是否有作用
$ dig @8.8.8.8 examplecat.com
examplecat.com. 17 IN A 104.248.50.87
没有改变。如果我询问其它的 DNS 服务器,它则知道新的 IP:
$ dig @1.1.1.1 examplecat.com
examplecat.com. 299 IN A 1.2.3.4
但是 8.8.8.8 仍然不知道。即使我5分钟前刚刚更改它,1.1.1.1 就可以得到新的 IP,大概是因为之前从来没有人查询过 1.1.1.1 中的 examplecat.com ,所以它的缓存中没有该数据。
名称服务器 TTLs 的时间更长
之所以我的域名注册商说”这将会在48小时内生效“,是因为 NS 记录中的 TTLs (这是递归服务器用来知道该查询哪个名称服务器的)要长的多。
新的名称服务器肯定会返回 examplecat.com
的新 IP 地址
$ dig @ns-cloud-b1.googledomains.com examplecat.com
examplecat.com. 300 IN A 1.2.3.4
但是还记得我们查询 github.com
的名称服务器发生了什么吗?
$ 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小时!所以与只更新 IP 地址而不更改你的名称服务器想比,名称服务器的更新通常需要更长的时间才能从缓存中过期和传播。
你的名称服务器如何更新?
当我为 examplecat.com
更新名称服务器时,这个 .com
域名会得到一个新的 NS
记录。就像这样:
$ dig ns @j.gtld-servers.net examplecat.com
examplecat.com. 172800 IN NS ns-cloud-b1.googledomains.com
但是新的 NS 记录是如何到达那里的呢?经过是这样的:我告诉我的域名注册商,我希望新的名称服务器是什么。然后域名注册商告诉 .com
名称服务器做更新。
对 .com
来说,更新是非常快的(在几分钟内),但是我认为对一些其它的 TLDs(顶级域名),TLD 名称服务器可能不会响应的很快。
你的项目的 DNS 解析器库可能也会缓存 DNS 记录
TTLs 在实际中不被遵守的另一个原因是:许多程序需要解析 DNS 名称,并且一些程序会在内存中无期限地缓存 DNS 记录(直到程序被重启)。
举例来说,AWS 有一篇文章: Setting the JVM TTL for DNS Name Lookups 。我还没有写过很多用于 DNS 查找的 JVM 代码。但是稍微搜索一下 JVM 和 DNS,似乎可以配置 JVM,使其无期限地缓存每个 DNS 查找(比如 this elasticsearch issue )。
以上就是全部了!
我希望这篇文章可以帮助你理解当更新你的 DNS 时发生了什么!
再次做为免责声明—— TTLs 不能绝对说明 DNS 的全部流程——一些递归服务器显然不会遵守 TTLs,即使像 8.8.8.8 这样的主地址也是如此。所以即使你只是用一个短 TTL 更新了一个 A 记录,实际上还是很有可能在一两天内仍旧获得的是旧 IP 地址。
另外,在发布完这篇文章后,我将 examplecat.com
的名称服务器修改回了原来的值。