# 06 | 域名里有哪些门道?
在上一讲里,我们学习了 HTTP 协议使用的 TCP/IP 协议栈,知道了 HTTP 协议是运行在 TCP/IP 上的。
IP 协议的职责是 网际互连 ,它在 MAC 层之上,使用 IP 地址把 MAC 编号转换成了四位数字,这就对物理网卡的 MAC 地址做了一层抽象,发展出了许多的「新玩法」。
例如,分为 A、B、C、D、E 五种类型,公有地址和私有地址,掩码分割子网等。只要每个小网络在 IP 地址这个概念上达成一致,不管它在 MAC 层有多大的差异,都可以接入 TCP/IP 协议栈,最终汇合进整个互联网。
但接入互联网的计算机越来越多,IP 地址的缺点也就暴露出来了,最主要的是它“对人不友好”,虽然比 MAC 的 16 进制数要好一点,但还是难于记忆和输入。
怎么解决这个问题呢?
那就「以其人之道还治其人之身」,在 IP 地址之上再来一次抽象,把数字形式的 IP 地址转换成更有意义更好记的名字,在字符串的层面上再增加「新玩法」。于是,DNS 域名系统就这么出现了。
# 域名的形式
在第 4 讲 曾经说过,域名是一个有层次的结构,是一串用 .
分隔的多个单词,最右边的被称为 顶级域名,然后是 二级域名 ,层级关系向左依次降低。
最左边的是主机名,通常用来表明主机的用途,比如 www
表示提供万维网服务、mail
表示提供邮件服务,不过这也不是绝对的,名字的关键是要让我们容易记忆。
看一下极客时间的域名 time.geekbang.org
,这里的 org
就是顶级域名,geekbang
是二级域名,time
则是主机名。使用这个域名,DNS 就会把它转换成相应的 IP 地址,你就可以访问极客时间的网站了。
域名不仅能够代替 IP 地址,还有许多其他的用途。
在 Apache、Nginx 这样的 Web 服务器里,域名可以用来标识虚拟主机,决定由哪个虚拟主机来对外提供服务,比如在 Nginx 里就会使用 server_name
指令:
server {
listen 80; # 监听 80 端口
server_name time.geekbang.org; # 主机名是 time.geekbang.org
...
}
2
3
4
5
域名本质上还是个 名字空间系统,使用多级域名就可以划分出不同的国家、地区、组织、公司、部门,每个域名都是独一无二的,可以作为一种身份的标识。
举个例子吧,假设 A 公司里有个小明,B 公司里有个小强,于是他们就可以分别说是「小明.A 公司」,「小强.B 公司」,即使 B 公司里也有个小明也不怕,可以标记为「小明.B 公司」,很好地解决了重名问题。
因为这个特性,域名也被扩展到了其他应用领域,比如 Java 的包机制就采用域名作为命名空间,只是它使用了反序。如果极客时间要开发 Java 应用,那么它的包名可能就是 org.geekbang.time
。
而 XML 里使用 URI 作为名字空间,也是间接使用了域名。
# 域名的解析
就像 IP 地址必须转换成 MAC 地址才能访问主机一样,域名也必须要转换成 IP 地址,这个过程就是 域名解析 。
目前全世界有几亿个站点,有几十亿网民,而每天网络上发生的 HTTP 流量更是天文数字。这些请求绝大多数都是基于域名来访问网站的,所以 DNS 就成了互联网的重要基础设施,必须要保证域名解析稳定可靠、快速高效。
DNS 的核心系统是一个三层的树状、分布式服务,基本对应域名的结构:
- 根域名服务器(Root DNS Server):管理顶级域名服务器,返回
com
、net
、cn
等顶级域名服务器的 IP 地址; - 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址;
- 权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com 权威域名服务器可以返回
www.apple.com
的 IP 地址。
在这里根域名服务器是关键,它必须是众所周知的,否则下面的各级服务器就无从谈起了。目前全世界共有 13 组根域名服务器,又有数百台的镜像,保证一定能够被访问到。
有了这个系统以后,任何一个域名都可以在这个树形结构里从顶至下进行查询,就好像是把域名从右到左顺序走了一遍,最终就获得了域名对应的 IP 地址。
例如,你要访问 www.apple.com
,就要进行下面的三次查询:
- 访问根域名服务器,它会告诉你
com
顶级域名服务器的地址; - 访问
com
顶级域名服务器,它再告诉你apple.com
域名服务器的地址; - 最后访问
apple.com
域名服务器,就得到了www.apple.com
的地址。
虽然核心的 DNS 系统遍布全球,服务能力很强也很稳定,但如果全世界的网民都往这个系统里挤,即使不挤瘫痪了,访问速度也会很慢。
所以在核心 DNS 系统之外,还有两种手段用来减轻域名解析的压力,并且能够更快地获取结果,基本思路就是 缓存 。
首先,许多大公司、网络运行商都会建立自己的 DNS 服务器,作为用户 DNS 查询的代理,代替用户访问核心 DNS 系统。这些「野生」服务器被称为「非权威域名服务器」,可以缓存之前的查询结果,如果已经有了记录,就无需再向根服务器发起查询,直接返回对应的 IP 地址。
这些 DNS 服务器的数量要比核心系统的服务器多很多,而且大多部署在离用户很近的地方。比较知名的 DNS 有 Google 的 8.8.8.8
,Microsoft 的 4.2.2.1
,还有 CloudFlare 的 1.1.1.1
等等。
其次,操作系统里也会对 DNS 解析结果做缓存,如果你之前访问过 www.apple.com
,那么下一次在浏览器里再输入这个网址的时候就不会再跑到 DNS 那里去问了,直接在操作系统里就可以拿到 IP 地址。
另外,操作系统里还有一个特殊的 主机映射 文件,通常是一个可编辑的文本,在 Linux 里是 /etc/hosts
,在 Windows 里是 C:\WINDOWS\system32\drivers\etc\hosts
,如果操作系统在缓存里找不到 DNS 记录,就会找这个文件。
有了上面的野生 DNS 服务器、操作系统缓存和 hosts 文件后,很多域名解析的工作就都不用跋山涉水了,直接在本地或本机就能解决,不仅方便了用户,也减轻了各级 DNS 服务器的压力,效率就大大提升了。
下面的这张图比较完整地表示了现在的 DNS 架构。
在 Nginx 里有这么一条配置指令 resolver
,它就是用来配置 DNS 服务器的,如果没有它,那么 Nginx 就无法查询域名对应的 IP,也就无法反向代理到外部的网站。
resolver 8.8.8.8 valid=30s; # 指定 Google 的 DNS,缓存 30 秒
# 域名的新玩法
有了域名,又有了可以稳定工作的解析系统,于是我们就可以实现比 IP 地址更多的新玩法了。
第一种,也是最简单的,重定向 。因为域名代替了 IP 地址,所以可以让对外服务的域名不变,而主机的 IP 地址任意变动。当主机有情况需要下线、迁移时,可以更改 DNS 记录,让域名指向其他的机器。
比如,你有一台 buy.tv
的服务器要临时停机维护,那你就可以通知 DNS 服务器:我这个 buy.tv 域名的地址变了啊,原先是 1.2.3.4,现在是 5.6.7.8,麻烦你改一下。DNS 于是就修改内部的 IP 地址映射关系,之后再有访问 buy.tv 的请求就不走 1.2.3.4 这台主机,改由 5.6.7.8 来处理,这样就可以保证业务服务不中断。
第二种,因为域名是一个名字空间,所以可以使用 bind9
等开源软件搭建一个在内部使用的 DNS,作为名字服务器。这样我们开发的各种内部服务就都用域名来标记,比如数据库服务都用域名 mysql.inner.app
,商品服务都用 goods.inner.app
,发起网络通信时也就不必再使用写死的 IP 地址了,可以直接用域名,而且这种方式也兼具了第一种玩法的优势。
第三种玩法包含了前两种,也就是 基于域名实现的负载均衡 。
这种玩法也有两种方式,两种方式可以混用。
- 第一种方式,因为域名解析可以返回多个 IP 地址,所以一个域名可以对应多台主机,客户端收到多个 IP 地址后,就可以自己使用轮询算法依次向服务器发起请求,实现负载均衡。
- 第二种方式,域名解析可以配置内部的策略,返回离客户端最近的主机,或者返回当前服务质量最好的主机,这样在 DNS 端把请求分发到不同的服务器,实现负载均衡。
前面我们说的都是可信的 DNS,如果有一些不怀好意的 DNS,那么它也可以在域名这方面做手脚,弄一些比较恶意的玩法,举两个例子:
- 域名屏蔽 ,对域名直接不解析,返回错误,让你无法拿到 IP 地址,也就无法访问网站;
- 域名劫持 ,也叫 域名污染,你要访问 A 网站,但 DNS 给了你 B 网站。
好在互联网上还是好人多,而且 DNS 又是互联网的基础设施,这些恶意 DNS 并不多见,你上网的时候不需要太过担心。
# 小结
这次我们学习了与 HTTP 协议有重要关系的域名和 DNS,在这里简单小结一下今天的内容:
- 域名使用字符串来代替 IP 地址,方便用户记忆,本质上一个名字空间系统;
- DNS 就像是我们现实世界里的电话本、查号台,统管着互联网世界里的所有网站,是一个超级大管家;
- DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存;
- 使用 DNS 可以实现基于域名的负载均衡,既可以在内网,也可以在外网。
# 课下作业
在浏览器地址栏里随便输入一个不存在的域名,比如就叫
www.
不存在.com
,试着解释一下它的 DNS 解析过程。浏览器缓存 -> 操作系统缓存 -> 操作系统 host 文件 -> dns 服务器
而 dns 服务器查找顺序为:非权威 dns 服务器 -> 根域名服务器 -> 顶级域名服务器 -> 二级域名服务器
如果因为某些原因,DNS 失效或者出错了,会出现什么后果?
失效:无法访问到该地址,域名屏蔽
出错:解析到了别人的地址,域名污染
# 课外小贴士
- 早期的域名系统只支持使用英文,而且顶级域名被限制在三个字以内,但随着互联网的发展限制已经解除了这些限制,可以使用中文作为域名,而且在 com、net、gov 等之外新增了 asia、media、museum 等许多新类别的顶级域名
- 域名的总长度限制在 253 个字符以内,而每一级域名长度不能超过 63 个字符
- 域名是大小写无关的,但通常都使用小写的形式
- 过长的域名或则过多的层次关系也会导致与 IP 地址同样难于记忆的问题,所以场景的域名大多是两级或三级,四级以上很少见
# 拓展问题
为何全世界只有 13 组根域名服务器呢?
细节原因不好解释,简单来说是因为 dns 协议还有 udp 协议里包大小的限制,只有 512 字节,再除以 dns 记录长度,最多 15 组,再去掉 buffer。
终极 dns 的解析是有谁实现的或者谁规定的
域名由专门的域名注册机构管理,终极的是ICANN。IP地址的分配也由 ICANN 管理,当然有浪费,美国是互联网的发明国,所以占用 ip 地址最多。ip 地址查找由专门的协议,比如 arp。
当域名所对应的 ip 发生变化的时候,因为上述说到有权威 dns 服务器(缓存),它是如何知道的?包括权威的 dns 服务器
域名解析有个 ttl 有效期,到期就会去上一级 dns 重新获取,当然也可以主动刷新。
比如我备案了一个域名 www.abc.com ,是不是 abc.com 就会注册到根域名服务器上,这个根域名服务器,顶级域名服务器也是某个公司开发的吗?
根和顶级 dns 由互联网组织 ICANN 管理,不属于任何公司。根 dns 只管理顶级 dns(如 com、cn)。
操作系统的 dns 缓存是什么?
在 Windows 上可以用命令行
ipconfig /displaydns
看缓存的 dns,存在系统内部。