对于开发同学来说,CDN 这个词,既熟悉又陌生。

平时搞开发的时候很少需要碰这个,但却总能听到别人提起。

我们都听说过它能加速,也大概知道个原因,但是往深了问。

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

就感觉有些懵了。但没关系,今天我们换个角度重新认识下 CDN。

CDN 是什么

对于数字和文本类型的数据,比方说名字和电话号码相关的信息。我们需要有个地方存起来。

我们通常会用 mysql 数据库去存。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

文本存在 mysql 中

当我们需要重新将这一数据取出的时候,就需要去读 mysql 数据库。

但因为 mysql 的数据是存在磁盘上的,单台实例,读性能到差不多 5kqps 就已经很不错了。

看起来还凑合,但对于稍微大一点的系统,就稍微有点捉急了。

为了提升点性能,我们在 mysql 之前再加一层内存做缓存层,比如常说的 redis,读数据优先到内存里读,读不到才到 mysql 里读,大大减少了读 mysql 的次数。有了这套组合拳,读性能轻松上万 qps。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

mysql 和 redis

好了,到这里,我们说的都是我们平时比较容易接触的开发场景。

但如果现在我要处理的,不再是上面提到的文本类数据,而是图片数据

比如,我有一张帅气的照片。就下面这张。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

每次刷某音听到有人翻唱蔡健雅的《letting go》的时候,我都忍不住想发这张图。

并配文 “还是忘不了”。

那么问题来了。

这张图片数据应该存在哪?,又该从哪里读?

我们回过头去看 mysql 和 redis 的场景,无非就是存储层加缓存层

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

存储层和缓存层

对于图片这样的文件对象存储层不太可能再用 mysql,应该改用专业的对象存储,比如亚马逊的 S3(Amazon Simple Storage Service,注意后面是三个 S 开头的单词,所以叫 s3),或者阿里云的 oss(Object Storage Service)。下面的内容,我们就用比较常见的 oss 去做解释。

缓存层,也不能继续用 redis 了,需要改成使用 CDNContent Delivery Network,内容分发网络)。

可以将 CDN 简单理解为对象存储对应的缓存层。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

CDN 和 OSS

现在就可以回答上面的提问,对用户来说,这张图片数据存在了对象存储那,当有需要的时候,会从 CDN 那被读出来。

CDN 的工作原理

有了 CDN 和对象存储之后,现在我们来看下他们之间是怎么工作的。

我们平时看到的图片,可以右键复制查看它的 URL。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1667103075060

会发现图片的 URL 长这样。

https://cdn.xiaobaidebug.top/1667106197000.png

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

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 节点返回数据。

上面第一阶段流程里,提到了很多新的名词,比如 CNAME,根域,一级域啥的,它们在之前写的 「DNS 中有哪些值得学习的优秀设计」有很详细的描述,如果不了解的话可以去看下。

我们知道 DNS 的目的就是通过域名去获得 IP 地址

但这只是它的众多功能之一。

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

对于普通域名,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
cdn.xiaobaidebug.top.w.kunlunaq.com. 300 IN A 122.228.7.251

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

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

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

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 中能不能读取到文本数据并展示一样。

当然能。

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1667101182393

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

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

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

回源是什么?

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

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

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1668605964836

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

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

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

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

有缓存直接返回和没缓存回源的区别

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

有。我们接着往下看。

怎么判断是否发生回源

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

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

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

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

查看 response header

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

回源的情况

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

那此时 CDN 里肯定是有这张图片的缓存了。我们可以试着再执行一次 GET 方法获取图片。

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1667095186020

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

这个是某里云的做法,其他比如腾某云啥的,也都大差不差,几乎都可以从 response header 里找到相关的信息。

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

看到这里我们就可以回答文章开头的问题了。

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

更新直接访问源站

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

更新走了 CDN 还回源

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

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

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

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

cdn 刷新预热

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

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1667344813600

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

从上面的描述看下来,CDN 最大的优势在于,对于来自世界各地的用户,它可以就近分配 CDN 节点获取数据,并且多次重复获取同一个文件数据的时候,有缓存加速的作用。

这对于网页图片这样的场景,是再合适不过了。因为底层用的是对象存储,也就是说,只要是文件对象,比如视频啥的,都可以用这套流程接入 cdn 做加速。比如平时刷的某音某手短视频就是这么干的。

那反过来想想,问题就来了。

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

如果你有一个公司内网的服务,并且服务请求的图片等文件不太可能被多次重复调用,这时候其实没必要使用 CDN。

注意上面两个加粗了的关键点。

• 内网服务,是为了保证你是了解服务的请求来源的,也能拿到对象存储的读权限,并且如果你的对象存储也是公司内部的,那大概率跟你的服务已经在同一个机房里,这已经很近了。接入 CDN 也享受不到 “就近分配 CDN 节点” 所带来的好处。

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

CDN 是什么,用了 CDN 就一定比不用更快吗-风君雪科技博客

1668612494972

关于上面的第二点,如果你需要一个明确的指标去说服自己,那我可以给你一个。从上面的介绍内容,我们知道,可以通过 cdn 响应的 http header 中的 X-Cache 字段,看到一个请求是否触发过回源,统计次数,再除以总的请求数,就能得到回源的比例,比如回源比例高达 90%,那还接啥 cdn。

总结

・ 对于文本类数据我们习惯用 mysql 做存储,redis 做缓存。但属于文件类数据,比如视频图片,则需要使用 oss 等做对象存储,cdn 做缓存。

・ 用了 CDN 如果发生回源,那实际上会比不用的时候更慢一些。

・ CDN 最大的优势在于,对于来自世界各地的用户,它可以就近分配 CDN 节点获取数据,并且多次重复获取同一个文件数据的时候,有缓存加速的作用。如果你的服务和对象存储都在内网,并且文件数据也不太会有重复使用的可能性,那其实没必要接入 cdn。

本文来自微信公众号:小白 debug (ID:xiaobaidebug),作者:小白