CDN 为什么这么设计?

过去几十年,计算机网络把几乎全世界的计算机都连接了起来,我们只要把静态资源和动态的代码部署到服务器上,然后启动服务监听某个端口,这样世界各地的计算机就都能访问该网站。

但是这样有个问题,资源最终还是通过物理层网络线路和设备传输的,每经过一段线路、一个网络设备都有一些耗时,所以客户端和服务器相距越远,网站打开速度就越慢。.

这就像你从海南买了一件东西,如果你人在广州的话,那可能很快就收到了,因为传输距离近,但如果你在北京的话,那可能就要多等几天了,因为中间经过的线路、节点都比较多。

但这样肯定不行的,用户体验会很差。怎么解决这个问题呢?

离得越远网站打开速度就越慢,很容易想到,如果部署到很多个地方,当用户访问网络的时候,访问最近的那个不就行了?

这就像快递都有一些中转的仓库,可以存放一些货物,如果你人在北京,要买一个海南的东西,恰好北京的仓库里有,那岂不是很快就可以收到了。

思路是没问题,但是怎么实现呢?

用户是通过域名访问网站的,那能不能通过 DNS 服务器来实现这个功能呢?

前面写过一篇 DNS 原理的文章,这里简单回顾下:

CDN 为什么这么设计?

客户端访问某个域名的时候,会先查找本地 hosts 文件,如果能查到 ip 就直接访问。

否则会向本地 DNS 服务器发请求,这个是联通、移动等运营商提供的每个城市都有的 DNS 服务器。由它去域名服务器发送解析域名的请求,然后把结果返给客户端。

域名是分层解析的,有根域名服务器、顶级域名服务器、权威域名服务器三层,比如 image.baidu.com 会先向根域名服务器发请求查询 com 的顶级域名服务器的 ip,然后再向 com 顶级域名服务器查询 image.baidu.com 的权威域名服务器的 ip。查询到权威域名服务器之后,任意层级的域名都会在这里解析(所以叫权威域名服务器)。

看到这个权威域名服务器的时候,不知道大家是否就想到怎么实现 CDN 网络了。

能不能在权威域名服务器这一层根据客户端的 ip 做一下负载均衡呢?比如北京来的 DNS 请求就返回北京机房的服务器的 ip,上海来的 DNS 请求就返回上海机房的服务器的 ip。

确实可以这样实现内容的就近分发,这样的负载均衡网络就叫做 CDN (Conent Delivery Network)

但是实现这样一个 CDN 网络需要在全国建立多个机房,成本太高了,所以只有像百度、阿里、腾讯这类大公司才会自建 CDN,一般情况下我们都会买第三方的 CDN 服务来用。

这些公司建好了 CDN 网络,实际上自己也是用不完的,也会对外提供 CDN 加速服务。

第三方的 CDN 服务自然也要提供一个 DNS 服务器,也就是实现根据 ip 返回不同城市的服务器的 ip 的那个。

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

CDN 为什么这么设计?

用户向本地 DNS 服务器发请求之后,经历根域名、顶级域名的 DNS 解析,最终会转给权威 DNS 服务器。这时候只要权威 DNS 服务器再转给 baidu 的 DNS 服务器就可以了,这样就能接入 CDN 服务。

baidu 的 DNS 服务器实现了负载均衡,会根据请求 ip  所在的城市,返回不同城市的服务器的 ip。也就实现了就近分发的网络加速功能。

那这个从权威 DNS 到 baidu 的 DNS 的转发是怎么实现的呢?

DNS 的记录有很多种类型,比如:

A 代表 address,记录域名对应的 ip。

CNAME 代表域名还有一个别名,可以向那个域名来查 ip。

MX 代表件名后缀对应的域名或者 IP

看到这个 CNAME 类型,大家应该就想到怎么实现转发了。

只要自己在 DNS服务器上配一条 CNAME 的记录,指向 CDN 服务器的域名就可以了。

比如你用某云的 CDN 的时候,第一步也是要配置下自己的 DNS 服务器的 CNAME 指向它:

CDN 为什么这么设计?

这样,当你访问某个域名的时候,解析域名的权威服务器会返回 CDN 服务的 DNS 服务器的域名,然后再向这台 CDN 的 DNS 服务器发送解析域名的请求,这时候它就可以根据 ip 所在城市来返回一个就近城市的服务器给你。

当然,也可以再做一层 CNAME 转发,比如 CDN 的 DNS 服务器把域名解析转给城市的 DNS 服务器,然后城市的 DNS 服务器再根据不同机器的负载情况来返回一台离得近而且负载比较小的服务器的 ip 给客户端。

这样客户端就能从最近的服务器下载静态资源,从而更快地打开网站。

如果访问的资源没有的时候,会向源站服务器发请求来拿对应的资源并且缓存下来,之后再此访问就不用访问源站了。

这个缓存时间是怎么指定的呢?

CDN 为什么这么设计?

CDN 服务会有一个控制台,可以设置不同资源的缓存时间,当然,请求的 header 里也有 expries 和 Cache-Control 来控制缓存时间,这俩的生效的优先级也是可以设置的。

这样的 CDN 服务国内和国外是分开的,如果网站目标用户只是国内的,那只需要买下国内的 CDN 服务,国外用户访问慢点就慢点,如果网站国外用户也很多,那还需要买下国外的 CDN 服务。

比如某云的国内 CDN 节点分布是这样的:

CDN 为什么这么设计?

海外的话则是另一套 CDN 网络:

CDN 为什么这么设计?

总结

为了加快网站打开速度,我们会使用 CDN 服务,它并不是一个网络协议,只是基于 DNS 协议实现的加速功能的网络。

它的原理就是域名的权威 DNS 服务器把请求转给 CND 的负载均衡的 DNS 服务器,然后根据 ip返回不同城市的 DNS 服务器,再根据负载来选择一台就近的服务器 的 ip 返回。

这样客户端就能从最近的负载最小的服务器拿到资源。

CDN 的缓存设置可以根据 header 来,也可以在控制台设置一些规则,这两者生效的优先级也可以设置。

CDN 网络的建设成本还是很大的,只有大公司会自建,一般我们都会买三方服务,而且国内和海外的 CDN 都是分开的,如果主要服务国内用户,那只买国内的 CDN 服务即可。

有了这套覆盖全国、全球的 CDN 节点网络之后,我们才能更快地打开网站。