阅读 37

「译」当你更新你的 DNS 时会发生什么

翻译自: jvns.ca/blog/how-up…

关于 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)做了什么。首先,如果它已经缓存了这些数据,那么将会直接使用缓存中的数据。但是如果所有的缓存都失效了该怎么办?它会做如下工作:

  1. 它的源代码中有根 DNS 服务器的 IP 地址。你可以参阅 [unbound's source code here](unbound's source code here) 。假如从 198.41.0.4 开始。下面有一些硬编码 IP 地址的官方来源: official source ,也称为『根提示文件』。

  2. 询问根域名服务器中的 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 名称服务器中的内容,但是我们假装我们真的是从零开始)

  3. 查询 .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 的名称服务器。

  4. github.com 名称服务器中查找关于 github.com 的信息。

    就快要结束了!

    $ dig @205.251.193.165 github.com
    
    github.com.		60	IN	A	140.82.112.4
    复制代码

    成功了!我们得到了 github.comA 记录!现在递归域名服务器取到了 github.com 的 IP 地址,并将其返回给了你。它可以仅通过硬编码几个 IP 地址(即根域名服务器)来实现所有的这些工作。

如何查看所有的递归 DNS 服务器的流程:dig +trace

当我想要了解一个递归服务器在解析一个域名时会做什么,我会运行:

$ dig @8.8.8.8 +trace github.com
复制代码

它会打印出请求的所有 DNS 记录(从根 DNS 服务器开始,会经过我们刚刚探讨过的4步)。

让我们来更新一些 DNS 记录

现在我们知道了 DNS 基本的工作流程,让我们更新一些 DNS 记录,看看会发生什么。

当你更新你的 DNS 记录时,主要有两个选择:

  1. 不修改名称服务器
  2. 修改名称服务器

谈谈 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.ca1.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 的名称服务器修改回了原来的值。