DNS,看不见但又必不可少的上网环节
介绍了域名、主机名、DNS等概念,以及在本机和局域网中 DNS 的相关流程

写在前面
今天是10月24日,被很多人称为程序员节,这是一个发源于中国软件社区的非官方节日,已有将近十年的历史。
在计算机领域,很多指标都是用二进制来度量的,例如存储容量。而在二进制中,1024,也就是2的10次方,又有着特殊的意义,因为它与1000很接近,这样就可以用我们熟知的10进制来进行近似计算了。
回顾
关于浏览器打开网页的过程,我上周做了简单的介绍。因为这是在我构建个人网站的过程中整理的,所以就把与网站生产端相关的部分也加了进来,就有了这张流程图。

这里面最关键的一个环节就是 DNS,不过 DNS 对普通用户而言是完全透明的,所以今天就详细介绍下这个不太能被看见的 DNS。
域名
之前说过,在计算机网络中,IP 是用来标识各个节点位置的,各个节点也是通过 IP 来访问其他节点的。但是 IP 都是由无意义的数字和字母组成,很难识别和记忆。随着网络规模的扩张,就需要一个便于人们记忆的主机访问方式。
于是在上世纪70年代,斯坦福研究院的网络信息中心便设计了“主机名(hostname)”的机制,也就是通过一个字符串,来标识网络中的主机,再使用一个文件 HOSTS.TXT 来记录主机名和 IP 的对应关系。如此,网络中的主机就可以通过易于记忆的主机名来访问其他节点了。
HOSTS.TXT 文件由斯坦福研究院集中管理,然后各个网络节点通过 FTP 协议来获取最新版本,并保存在本地。当需要访问网络中其他节点时,只需要知道主机名,计算机就可以通过本地的 HOSTS.TXT 文件将主机名转换为 IP,来进行网络访问。
但随着网络规模的极速扩张,主机名的机制也暴露出越来越多的问题,比如,更新不及时,文件过大导致带宽压力,安全性低等。于是到了80年代,人们又发明出了一种更具扩展性的机制,就是 DNS,域名系统。
单说域名的话,它跟主机名相比只是多了一些句点,但正是这些句点,使得一个名字有了层次,为未来无比庞大的网络提供了一个可扩展的基础。
虽然有了 DNS,但是主机名的机制并没有废弃,而是沿用至今。也许你也见过,就是我们平时说的 hosts 文件,对于 Windows 系统是C:\Windows\System32\drivers\etc\hosts,而 Linux 和 Mac 是/etc/hosts。
hosts 文件的内容就是主机名与 IP 的对应关系,一般使用时,大多数情况下都会把这个主机名写成域名,然后绑定上本机 IP,或是测试环境 IP。例如:
# hosts
127.0.0.1 localhost
192.168.2.17 www.laidbackgeek.com
因为 hosts 的优先级高于 DNS,所以绑定 hosts 之后,在本地访问这个域名时,会优先使用 hosts 中绑定的 IP,就可以访问到开发或测试环境的服务器,而不会直接访问到生产环境的服务,这样就可以方便地进行开发和测试,尤其是多系统联合测试。
注:主机名对应的规范是:RFC952,域名系统对应的规范是:RFC1034 和 RFC1035
DNS
在上一篇文章里,我对 DNS 相关的流程做了极大的简化,只是说电脑联网时获取到了 DNS 地址,然后浏览器根据域名,通过 DNS 找到对应的 IP,就能访问网站对应的服务器了。
在一般的家庭宽带中,你电脑或手机获取到的 DNS 服务器地址往往是你家路由器的地址,也就是说你的手机电脑并不会直接访问 DNS 服务器,而是先访问路由器,再由路由器向 DNS 服务器发起请求。
这里的路由器有两个作用,一是转发 DNS 查询请求,二是缓存查询结果。这样当短时间内有相同域名的 DNS 查询时,可以直接从缓存中获取结果,而不用重复请求 DNS 服务器了。而这样的 DNS 缓存,在你的电脑上也有,还不只一处。
咱们从头说起。当浏览器访问一个域名时,首先就是检查浏览器中的 DNS 缓存,如果有就直接使用了,如果没有,还会去检查操作系统的 DNS 缓存,有就用,如果还没有,还会检查操作系统的 hosts 文件,就是我上面提到的仍保留至今的主机名机制。
所以,尽管 hosts 文件的优先级总体上是高于 DNS 的,但是却低于本地的 DNS 缓存,所以有时修改完 hosts 文件后,并不会立刻生效,需要稍等一会,或者清空一下的本地的 DNS 缓存。
若 hosts 文件中也没有,才会向系统中配置的 DNS 地址发起请求,在一般的家庭宽带中就是路由器,同样,路由器也是先检查自己的 DNS 缓存,如果没有,路由器才会向真正的 DNS 服务器发起查询请求。
如果 DNS 服务器返回了结果,那么刚才提到的所有 DNS 缓存的环节,都会缓存这个结果,以供下次查询使用。每一层的缓存时间原则上是遵循查询到的解析记录中的 TTL(Time To Live),不过不同的设备或组件的实现方式不可,可能会有一些其他限制,例如会限制最长缓存时间等。

当路由器请求 DNS 服务器时,也不是直接就能查询到结果的,这个 DNS 服务器是运营商提供的一个 DNS 查询服务,也只是整个 DNS 系统的一部分而已。
在 DNS 规范中,它被称为递归解析器(Recursive Resolver),它负责接受客户端请求,也就是来自电脑、手机等各个终端的 DNS 查询请求,然后通过递归的方式,查询到最终的域名解析记录。
随着网络规模的极速扩张,如果还像早期主机名机制那样,把所有域名和 IP 的对应关系都放在一起,那查询起来效率肯定特别低。于是必须使用一些架构风格,使查询过程既高效,又能适应互联网的巨大规模。
前面讲过的查询过程中,已经涉及到一些架构风格了,只不过很多架构风格我们已经习以为常,很难注意到了,比如缓存。而递归解析器查询 DNS 的方式涉及到的架构风格,你也许已经猜到了,就是分层。
下一篇文章,我会继续来讲 DNS 是如何实现分层递归查询的,同时我也会从架构风格的角度,讲一讲 DNS 系统涉及到的五种架构风格。