Administrator
发布于 2024-07-11 / 2 阅读
0

CDN请求过程详解

CDN简介

CDN大家比较熟悉,这里做个简单介绍。

CDN主要是让用户访问资源的时候,能从离用户距离很近的CDN节点进行获取,不必到真正提供服务的机器上获取。所以CDN可以

  1. 让用户更快的获取所需要的内容

  2. 减少骨干网络的流量

  3. 减少服务器的压力

CDN的工作原理

https://cdn.xiaobaidebug.top/1667106197000.png 浏览器输入之后的所有流程

其中前面的cdn.xiaobaidebug.top就是CDN的域名,后面的1667106197000.png是图片的路径名。

当我们在浏览器输入这个URL就会发起HTTP GET请求,然后经历以下过程。

CDN的查询流程

第一阶段: 你的电脑会先通过DNS协议获得cdn.xiaobaidebug.top这个域名对应的IP。

  • • step1和step2:先查看浏览器缓存,再看操作系统里的/etc/hosts缓存,如果都没有,就会去询问最近的DNS服务器(比如你房间里的家用路由器)。最近的DNS服务器上有没有对应的缓存,如果有则返回。

  • • step3:如果最近的DNS服务器上没有对应的缓存,就会去查询根域,一级域,二级域,三级域服务器。

  • • step4:然后,最近的DNS服务器会得到这个cdn.xiaobaidebug.top域名的别名(CNAME),比如cdn.xiaobaidebug.top.w.kunlunaq.com

  • • kunlunaq.com是阿里CDN专用的DNS调度系统

  • • step5到step7:此时最近的DNS服务器会去请求这个kunlunaq.com,然后返回一个离你最近的IP地址返回给你。

第二阶段: 对应上图里的step8。浏览器拿着这个IP去访问cdn节点,然后,cdn节点返回数据。

DNS消息有很多种类型,其中A类型,就是用域名去查域名对应的IP地址。而CNAME类型,则是用域名去查这个域名的别名

对于普通域名,DNS解析后一般就能直接得到域名对应的IP 地址(又叫A类型记录,A指Address)。

比如下面,我用dig命令发出DNS请求并打印过程数据。

$ dig +trace xiaobaidebug.top
;; ANSWER SECTION:

xiaobaidebug.top. 600 IN A 47.102.221.141

可以看到xiaobaidebug.top直接解析得到对应的IP地址47.102.221.141

但对于cdn域名,一波查询下来,先得到的却是一条CNAME的记录xx.kunlunaq.com,然后dig这个xx.kunlunaq.com才能得到对应的IP地址

$ dig +trace cdn.xiaobaidebug.top

cdn.xiaobaidebug.top. 600 IN CNAME cdn.xiaobaidebug.top.w.kunlunaq.com.
 
$ dig +trace cdn.xiaobaidebug.top.w.kunlunaq.com
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.243
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.241
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.244
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.249
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.248
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.242
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.250

看到这里,问题就又来了。

为什么要加个CNAME那么麻烦?

CNAME里指向的,其实是CDN专用的DNS域名服务器,它对整个DNS体系来说,只是其中一台小小的DNS域名服务器,看起来就跟其他域名服务器一样,平平无奇。DNS请求也会正常打入这个服务器里。

但当请求真正打到它上面的时候,它的特别之处就体现出来了,当查询请求打入域名服务器时,普通的DNS域名服务器返回域名对应的部分IP就够了,但CDN专用的DNS域名服务器却会要求返回离调用方"最近的"服务器IP。

CDN专用的DNS解析服务器会返回就近的CDN节点IP

怎么知道哪个服务器IP里调用方最近?

可以看到"最近"这个词其实是加了双引号的。

CDN专用的DNS域名服务器其实是CDN提供商提供的,比如阿里云当然知道自己的的CDN节点有哪些,以及这些CDN服务器目前的负载情况和响应延时甚至权重啥的,并且也能知道调用方的IP地址是什么,可以通过调用方的IP知道它所属的运营商以及大概所在地,根据条件筛选出最合适的CDN服务器,这就是所谓的"最近"。

举个例子。假设地理位置最近的CDN机房流量较多,响应较慢,但地理位置远一些的服务器却能更好的响应当前请求,那按理说可能会选择地理位置远一些的那台CDN服务器。

也就是说,选出来的服务器不一定在地理位置最近,但一定是当前最合适的服务器。

回源是什么

上面的图片URL,是https://cdn域名/图片地址.png的形式。

也就是说这张图片是访问CDN拿到的。

那么,直接访问对象存储能不能拿到图片数据并展示?

比如像下面这样。

https://oss域名/图片地址.png

这就像问,不走redis,直接从mysql中能不能读取到文本数据并展示一样。

当然能。

我之前放在博客里的图片就是这么干的。

但这样成本更高,这里的成本,可以指性能成本,也可以指调用成本。看下下面这个图。

可以看到直接请求oss的费用差不多是通过cdn请求oss的两倍,考虑到家境贫寒,同时也为了让博客获取图片的速度更快,我就接入了CDN。

但看到这里,问题又又来了。

上面的截图里,红框里有个词叫"回源"。

回源是什么?

当我们访问https://cdn域名/图片地址.png时,请求会打到cdn服务器上面。

但cdn服务器本质上就是一层缓存,并不是数据源,对象存储才是数据源

第一次访问cdn获取某张图片时,大概率在cdn里并没有这张图片的数据,因此需要到数据那去取出这份图片数据。然后再放到cdn上。下次再次访问cdn时,只要缓存不过期,就能命中缓存直接返回,这就不需要再回源。

于是访问的过程就变成了下面这样。

那还有哪些情况会发生回源呢?

除了上面提到的cdn上拿不到数据会回源站外,还有cdn上的缓存过期失效了也会导致回源站。

另外,就算有缓存,且缓存不过期,也可以通过cdn提供的开放接口来触发主动回源,但这个我们比较少机会能接触到。

另外,回源这个事情,其实用户是感知不到的,因为用户去读图片的时候,只能知道自己读到了还是读不到。

同样是读到了,还细分为是从cdn那直接读的,还是cdn回源读对象存储之后返回的

那么,我们有办法判断是否发生过回源吗?

有。我们接着往下看。

怎么判断是否发生回源

我们以某里云的对象存储和CDN为例。

假设我要请求下面这张图https://cdn.xiaobaidebug.top/image/image-20220404094549469.png

为了更方便的查看响应数据的http header,我们可以用上postman

通过GET方法去请求图片数据。

然后通过下面的tab切换查看response header信息。

\此时查看response header下的X-Cache的值是 MISS TCP_MISS。意思是未命中缓存导致CDN回源查oss,拿到数据后再返回。

X-Cache的值就变成了 HIT TCP_MEM_HIT,这就是命中缓存了。

用了CDN一定比不用的更快吗?

如果没有接入CDN,直接访问源站,流程是这样的。

如果接入了CDN,且CDN上没有缓存数据,那就会触发回源。

相当于在原来的流程上还多了一层CDN的调用流程。

也就是,用了CDN时,未命中CDN缓存导致回源,就会比不用的时候更慢。

未命中缓存,可能是cdn里压根就没这一数据,也可能是曾经有这条数据但后来过期失效了

这两种情况都正常,大部分时候并不需要做任何处理。

但对于极个别场景,我们可能需要做些优化。比如你们源站数据有大版本更新,就像更换cdn域名啥的,那在上线的那一刻用户全用新cdn域名去请求图片啥的,新CDN节点基本上百分百触发回源,严重的时候甚至可能会拖垮对象存储。这时候你可能需要提前将热点数据筛选出来,利用工具预先请求一波,让CDN加载上热数据缓存。比如某里云上的CDN就有这样的"刷新预热"功能。

当然也可以通过灰度发布的模式,先让少量用户体验新功能,让这些用户把cdn"热"起来,然后再逐步放开流量。

还有就是曾经有这条数据但后来过期失效了,对于热点数据,可以适当提高一下cdn数据的缓存时间

什么情况下不应该使用CDN?

  1. 内网服务,接入CDN也享受不到"就近分配CDN节点"所带来的好处。

  2.  图片或其他文件不太可能被多次重复使用,如果接入了CDN,那你每次去访问CDN获取图片的时候,CDN节点上大概率没有你要的数据,相当于每次都需要回源到对象存储去取一把。那接入CDN相当于给自己加了一层代理,多一层代理,就多一层耗时。