当你在浏览器输入一个网址到你看到页面上呈现出所有内容,这中间经历了哪些过程?
这两天当我在研究这个过程的时候,我注意到其中DNS解析这一环节非常的重要,值得仔细探讨。
1、什么是DNS?
DNS是域名系统(Domain Name System)的缩写,它是互联网的一项服务。
DNS在万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用刻意去记这种只有机器才能读取的IP字符串。
当我们在浏览器输入一个非IP地址类型的网址时,DNS就会将该域名转换为其对应的IP地址。这种通过域名,最终得到该域名对应的IP地址的过程叫做域名解析。
2、域名结构
说到域名的结构,我们先回顾一些一个网址URL的结构。
网址URL结构:
1 | [协议protocol]//[域名hostname][端口号port][文件路径path][请求参数query][hash值] |
eg:https://www.example.com:8801/home?name=rain#b52e96
就其中的域名 www.example.com 来说,它本身的结构也比较复杂。它是一个树形的结构,根节点root是“.”。这个域名完整的书写形式其实是 www.example.com.,只不过是我们不用写,浏览器或者系统的解释器会自动帮我们补全。
我们要想获取根域都有哪些,可以在终端下直接使用Linux命令查看:
1 | $ dig |
我们可以看到有 13 个根域,如 l.root-servers.net.
b.root-servers.net.
e.root-servers.net.
等等。
根域下面是顶级域,按照功能划分,顶级域划分为通用顶级域 (com、org、net 等)和国家与地区顶级域(cn、hk、us、tw 等)。
我们可以使用Linux命令追踪com域名的解析过程:
1 | $ dig com +trace |
打印出来的信息上反映,DNS解析会先去根域查找,然后根告诉说你找的 com
在这里,就是 com. 172800 IN NS [a-m].gtld-servers.net.
。
这里的 NS 指的是NameServer,大部分情况下我们称为权威名称服务器,简称权威。
顶级域下面是 example
这些我们熟悉的一级域。
再用命令看下解析过程:
1 | $ dig example.com. +trace |
可以看到,比 查询 com 的时候多了 example.com. 172800 IN NS ns[4-7].example.com.
这些, 到现在, example.com 解析过程可以描述为:
- 我想知道 example.com 的信息。好嘞,先去根域上看看。
- 来到了根这儿,根域一看。哦,example.com 是 com 的小弟,我只有 com 的信息,你去问问 com 吧。
- 好嘞,屁颠屁颠的根据根给的信息,就去找 com 了。
- com 哥,example.com 在你这里吧。稍等,我看下。恩,在的,不过我只记录了他们家权威的家庭住址,至于家里有几个娃几条狗我就不清楚了,你根据这个信息去找吧。
- 好嘞,然后辗转来到了帝都(假定example.com注册地是北京),感叹了一句,原来你在这里啊。
综上所述,域名结构 是:
1 | [二级域名].[一级域名].[顶级域名].(根域名) |
其中根域名省略了,顶级域是 com
,一级域名是 example
,二级域名是 mobile
。
由此可见,一个域名是由几部分(有可能只是一部分,也许是两部分,三部分…)组成的简单结构,它被点分隔,并 需要从右到左阅读。【参考MDN中域名的介绍】
3、DNS解析过程
当我们想在浏览器中查看一个网页的时候,输入域名比输入IP地址简单多了。那域名是如何被DNS解析成IP地址的呢?大概是这样的过程:
你在浏览器地址栏输入 example.com 。如果你的计算机hosts文件中有该域名和其IP的对应关系,那么这个域名就会被转换为IP地址,然后浏览器与网络服务器建立连接,实现通信。
如果你的计算机不知道 example.com 域名对应的IP,那么它会询问本地DNS服务器,由DNS服务器来解析该IP地址。
首先它会向你的 ISP(互联网服务提供商) 相关的 DNS 服务器 发送 DNS query。然后这些 DNS 进行递归查询。所谓的递归查询,就是能够直接返回对应的IP地址,而不是其他的 DNS 服务器地址。这个有别于后面提到的迭代查询。
如果上述的 DNS Servers 没有你要的域名地址,则就会发送迭代查询,先从 根域名(root)找起。即本地DNS服务器会将请求转发给根域名服务器。 假如你要查询 example.com ,会先从包含根结点的 13 台根域名服务器开始查询。
接着,以从右向左的方式递进,找到 com。 然后向包含 com 的 TLD (顶级域名) nameservers 发送 DNS 请求。接着找到包含 example 的 DNS server。
现在进入到了example.com 部分,即是现在正在询问的是权威服务器NS,该服务器里面包含了你想要的域名信息,也就是拿到了最后的结果 record 。
递归查询的 DNS Server 接受到这 record 之后, 会将该record 保存一份到本地。 如果下一次你再请求这个 domain 时,我就可以直接返回给你了。由于每条记录都会存在 TLL ,所以 server 每隔一段时间都会发送一次请求,获取新的 record,
现在电脑知道了要请求的IP地址,你的浏览器就能够与网络服务器交换内容了。
# 从客户端到本地DNS服务器是属于递归查询,而DNS服务器之间就是的交互查询就是迭代查询。
4、DNS实现原理
DNS服务器架构设计 大致如下:
问题1. DNS为什么不采用单点的集中式的设计方式,而是使用分布式集群的工作方式?
DNS的一种简单的设计模式就是在因特网上只使用一个DNS服务器。
该服务器包含所有的映射,在这种集中式的设计中,客户机直接将所有查询请求发往单一的DNS服务器,同时该DNS服务器直接对所有查询客户机做出响应。
尽管这种设计方式非常诱人,但他不适用当前的互联网,因为当今的因特网有着数量巨大并且在持续增长的主机,这种集中式设计会有:
- 单点故障(一旦出了问题,全球网络都将瘫痪)
- 通信容量(上亿台主机发送的查询DNS报文请求,包括但不限于所有的HTTP请求,电子邮件报文服务器,TCP长连接服务)
- 远距离的时间延迟(澳大利亚到纽约的举例)
- 维护开销大(因为所有的主机名-ip映射都要在一个服务站点更新)等问题。
【参见知乎回答:https://www.zhihu.com/question/23042131/answer/66571369】
所以这种理想的集中式设计是不符合现实情况的,只能选择使用分布式的层次数据库模式以及缓存方法来解决单点集中式的问题。通俗讲,DNS服务器的架构就像是一课树,DNS的解析过程就是利用这棵“域名树”来实现的。
问题2. 为什么要设置一个本地DNS服务器,它的作用是什么?
先假设没有本地DNS服务器的情况。
我们访问 www.edu.cn.,如果本地hosts查不到对应IP地址,那么会首先将域名发给根域,根域名服务器会告诉查询者cn顶级域所在的服务器的地址。
根域回答说“我这里没有你要的完整域名的地址,但是我可以告诉你cn这一层的域名在哪查询”。这样请求者虽然没有拿到最终的IP地址,但是也找到了下一个可以问的地方。
于是他再次将 www.edu.cn. 完整的发给cn域的服务器,cn域服务器一看,自己也不能给出整个地址的IP地址,于是又告诉查询者到edu域去查询。
以此类推,最终访问到了www这一层,终于如愿以偿地拿到了该域名对应的IP地址。
但如果每一个需要上网的终端都去向根域名服务器查询域名,那么这个访问量也是非常庞大的,似乎这棵树也没有解决问题。既然每一个人都要去做这个查询的过程,那么为什么不把这个繁重而又枯燥的过程交给一个固定的终端去做呢?
是的,我们的终端设备上找不到某个域名的IP地址时,并不是直接去访问根域名服务器,而是去访问一个本地的另一台域名服务器。
这台服务器专门做向“域名树”查询和记录的工作。由于有了一台专门的服务器,并且他是共享给很多终端设备使用的,那么就可以在其上面做一些必要的缓存,这样的服务器可以根据需要任意设置,不受地域网络状况的限制。这也就是前文中提到的网络服务提供商分配给我们的域名服务器地址。
他会检查每一次查询,如果该查询已经有人查过了,那么他会从缓存中给出结果直接返回。那缓存的实效性是怎么控制的呢?协议中对这个有规定,由查询服务提供者在查询结果中给出域名地址的有效时间。
如果过期了,则需要再次到“域名树”中去查询。这台专门用于查询域名的服务器接受网络上面的终端设备的查询,同时又向“域名树”查询,并对最终的用户负责,返回最终得到的IP地址,并将本次过程中查询到的所有结果、中间结果进行缓存,以便下一次查询同样的域名时访问。
由于个人经验有限,文中如有理解错误,欢迎指出。谢谢 :)
参考文档:
无线性能优化:域名收敛 | Taobao FED | 淘宝前端团队
【前端性能】浅谈域名发散与域名收敛 · Issue #1 · chokcoco/cnblogsArticle
- 本文作者: 敲完代码再睡觉
- 本文链接: https://teamonn.github.io/2018/03/20/DNS解析的全过程 以及 DNS实现的原理/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!