DNS (Domain Name System)是我们每天都用到的协议,CDN (Content Delivery Network)也经常会接触到,但你能说出它们的原理么?

能说出原理的话,有抓包看过它们真实的数据包么?

今天我们就一起通过抓包来深入下 DNS 流程和 CDN 原理吧。

DNS 实现原理

DNS 的流程可以看这张图:

抓包理解 DNS 流程和 CDN 原理_前端

浏览器访问了某个域名,首先会查找浏览器缓存、本地 hosts 文件、DNS 缓存,没有找到的话再去请求本地 DNS 服务器,由它负责完成域名的解析。

本地 DNS 会依次请求根域名服务器拿到对应的顶级域名服务器的地址,然后请求顶级域名服务器,拿到权威域名服务器的地址,之后权威域名服务器会返回最终的 IP 给本地 DNS 服务器,由它再返给浏览器。

比如说 baidu.com 这个域名,根域名是 .,顶级域名(也叫一级域名)是 com,而二级域名是 baidu.com,那会先向根域名服务器查找 com 的顶级域名服务器的地址,然后再向 com 的顶级域名服务器查找 baidu.com 的权威域名服务器的地址。

有的同学可能会问,那 image.baidu.com 或者 xx.yy.zz.baidu.com 呢?

二级域名和更多级的域名都在权威域名服务器解析,域名服务器只有三级。

因为域名服务器之所以这样分级是为了通过负载均衡来分散压力,具体的域名解析都是由各自的权威域名服务器来处理的,根域名和顶级域名服务器只是做了个转发。

三级就已经能达成目的了,更多级可以自己分,比如后面会讲的 CDN 服务就是自己做了更多级的负载均衡。

说到了 CDN,那 CDN 与 DNS 是啥关系呢?

CDN 的实现原理

CDN 不是一种协议,只是基于 DNS 协议实现的一种分布式网络。

前面说到顶级域名和二级域名服务器只是做了转发,最终域名解析都是在权威域名服务器做的。

那权威域名服务器是不是可以再做一层转发呢?

比如下面是百度云 CDN 的原理图:

抓包理解 DNS 流程和 CDN 原理_缓存_02

权威 DNS 服务器通过 CNAME 的配置(DNS 协议里指定别名的方式)把请求转发到了 baidu 的 DNS 服务器,baidu 的 DNS服务器再根据 IP 返回用户所在区域的一台机器的 IP。

这样用户从这个域名下载内容的时候,就找到了最近的一台机器,那速度自然快很多。

这就是 CDN 的原理。

大概介绍了 DNS 和 CDN 的实现原理,下面我们通过抓包来验证下。

抓包验证上述结论

我们一步步来,首先,前面讲到这三级查找是对的么?

抓包理解 DNS 流程和 CDN 原理_缓存_03

浏览器缓存和 DNS 缓存真的存在么?真的会查 hosts 文件么?

我们用抓包工具来验证下:

这种网络包需要用 wireshark 来抓。

抓包理解 DNS 流程和 CDN 原理_JavaScript_04

抓取网卡的数据包,过滤 DNS 的包:

抓包理解 DNS 流程和 CDN 原理_前端_05

刷新页面就可以看到所有 DNS 数据包了:

抓包理解 DNS 流程和 CDN 原理_JavaScript_06

然后你可以打开 chrome://net-internals/#dns ,查询某个域名的浏览器 DNS 缓存:

抓包理解 DNS 流程和 CDN 原理_JavaScript_07

点击按钮可以清掉浏览器 DNS 缓存:

抓包理解 DNS 流程和 CDN 原理_缓存_08

这证明了浏览器缓存的存在。

我们再往下验证,hosts 真的会生效么?

修改下 hosts 文件,加个配置:

抓包理解 DNS 流程和 CDN 原理_JavaScript_09

用 ping 命令试了下,真的生效了,这说明 DNS 确实会查询 hosts 文件。

抓包理解 DNS 流程和 CDN 原理_服务器_10

然后继续验证下系统的 DNS 缓存真的存在么?

抓包理解 DNS 流程和 CDN 原理_服务器_11

我 ping 了几次 ​​www.baidu.com,都没有新的​​ DNS 数据包,说明确实是有缓存的。

可以执行这个命令清掉系统 DNS 缓存: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

抓包理解 DNS 流程和 CDN 原理_后端_12

我 ping 了两次 ​​www.baidu.com​​ 都没有 DNS 数据包,但是我一清空缓存,再 ping 就有了:

抓包理解 DNS 流程和 CDN 原理_后端_13

这验证了系统级别的 DNS 缓存确实存在。

也就是说浏览器 DNS 缓存、hosts 文件、系统 DNS 缓存这三步确实都是会经历的:

抓包理解 DNS 流程和 CDN 原理_服务器_14

继续往下看,本地 DNS 服务是啥?

这个可以在“系统偏好设置 > 网络 > 高级”里看到:

抓包理解 DNS 流程和 CDN 原理_缓存_15

确实是有本地 DNS 服务器的地址的,这个一般是运营商提供的,可能每个城市都有一些公共的。这一级也有缓存。

通过这层层缓存加上域名系统本身就是分布式的,这种设计极大的减轻了 DNS 服务器的压力,实现了高并发,这是我们每天都在用的高并发系统。

继续往后看,这三级域名服务怎么验证呢?

抓包理解 DNS 流程和 CDN 原理_服务器_16

可以 ping 一个不存在的域名,比如 ddd1111.com

抓包理解 DNS 流程和 CDN 原理_前端_17

这时候可以看到请求了 com 的域名服务器,地址是 a.gtld-server.net,没错,这个就是一个顶级域名服务器的域名。

抓包理解 DNS 流程和 CDN 原理_JavaScript_18

但你再请求一个别的域名,你会发现它并没有从根域名顶级域名开始查,而是直接从权威域名服务器开始的:

抓包理解 DNS 流程和 CDN 原理_服务器_19

没错,这也是缓存,本地 DNS 服务器会把域名对应的权威域名服务器的 IP 缓存下来,直接去那里查。

你会发现有的返回结果是 CNAME,值为一个域名,这个 CNAME 是一种记录类型,别名的意思。之后会再去这里查,最后查到 A 的记录类型,值就是 IP 了。

CDN 就是这么实现的,我们来看一个真实的 CDN 的 DNS 查询的例子:

这是 ​​www.baidu.com​​ 的 DNS 查询结果:

抓包理解 DNS 流程和 CDN 原理_缓存_20

你会发现先通过 CNAME 指向了另一个域名,然后这个域名又给了两条 IP 的结果。

对照下 CDN 的原理图,就知道这俩 IP 都是离用户最近的服务器的 IP 了:

抓包理解 DNS 流程和 CDN 原理_缓存_21

这就是 CDN 的原理。

再来看个 ​​www.juejin.cn​​ 的,他也是用了 CDN 的:

抓包理解 DNS 流程和 CDN 原理_前端_22

也是同样 CNAME 指向了 CDN 的 DNS 服务器,然后返回了就近的一些服务器的 IP,只不过它的负载均衡的机器更多一些。

总结

我们通过 wireshark 抓包的方式,验证了 DNS 的流程和 CDN 的实现原理。

DNS 的流程是会先查找浏览器 DNS 缓存、hosts 文件、系统 DNS 缓存,然后请求本地 DNS 服务器,由它去一级级查询最终的 IP:

抓包理解 DNS 流程和 CDN 原理_服务器_23

CDN 是基于 DNS 的,在权威域名服务器做了 CNAME 的转发,然后根据请求 IP 的所在地来返回就近区域的服务器的 IP。

抓包理解 DNS 流程和 CDN 原理_服务器_24

这个流程是有一层层的缓存的,而且还是分布式的,是我们接触最多的高并发系统了。