对于开发同学来说,CDN这个词,既熟悉又陌生。平时搞开发的时候很少需要碰这个,但却总能听别人提起。我们都听过它能加速,也大概知道个原因,但是往深了问就感觉有些懵了。没关系,今天我们换个角度重新认识下CDN。
CDN和OSS概念
对于数字和文本类型的数据,比方说名字和电话号码相关的信息,我们需要有个地方存起来。我们通常会用Mysql数据库去存。
当我们需要重新将这一数据取出的时候,就需要去读Mysql数据库。
但因为Mysql的数据是存在磁盘上的,单台实例,读性能到差不多5kQPS就已经很不错了。
看起来还凑合,但对于稍微大一点的系统,就稍微有点捉急了。
为了提升点性能,我们在Mysql之前再加一层内存做缓存层,比如常说的Redis,读数据优先到内存里读,读不到才到Mysql里读,大大减少了读Mysql的次数。有了这套组合拳,读性能轻松上万QPS。
好了,到这里,我们说的都是我们平时比较容易接触的开发场景。
但如果现在我要处理的,不再是上面提到的文本类数据,而是图片数据。
那么问题来了。
这张图片数据应该存在哪?,又该从哪里读?
我们回过头去看Mysql和Redis的场景,无非就是存储层+缓存层。
对于图片这样的文件对象,存储层不太可能再用Mysql,应该改用专业的对象存储,比如亚马逊的S3(Amazon Simple Storage Service,注意后面是三个S开头的单词,所以叫s3),或者阿里云的OSS(Object Storage Service)。下面的内容,我们就用比较常见的oss去做解释。
而缓存层,也不能继续用Redis了,需要改成使用CDN(Content Delivery Network,内容分发网络)。
可以将CDN简单理解为对象存储对应的缓存层。
现在就可以回答上面的提问,对用户来说,这张图片数据存在了对象存储那,当有需要的时候,会从CDN那被读出来。
CDN的工作原理
有了CDN和对象存储之后,现在我们来看下他们之间是怎么工作的。
我们平时看到的图片,可以右键复制查看它的URL。
会发现图片的URL长这样。
https://cdn.juechen.top/3859625793501.png
其中前面的cdn.juechen.top
就是CDN的域名,后面的3859625793501.png
是图片的路径名。
当我们在浏览器输入这个URL就会发起HTTP GET请求,然后经历以下过程。
第一阶段: 你的电脑会先通过DNS协议获得cdn.juechen.top
这个域名对应的IP。
• step1和step2:先查看浏览器缓存,再看操作系统里的/etc/hosts
缓存,如果都没有,就会去询问最近的DNS服务器(比如你房间里的家用路由器)。最近的DNS服务器上有没有对应的缓存,如果有则返回。
• step3:如果最近的DNS服务器上没有对应的缓存,就会去查询根域,一级域,二级域,三级域服务器。
• step4:然后,最近的DNS服务器会得到这个cdn.juechen.top
域名的别名(CNAME),比如cdn.juechen.top.w.kunlunaq.com
。
• kunlunaq.com
是阿里CDN专用的DNS调度系统。
• step5到step7:此时最近的DNS服务器会去请求这个kunlunaq.com
,然后返回一个离你最近的IP地址返回给你。
第二阶段: 对应上图里的step8。浏览器拿着这个IP去访问cdn节点,然后,cdn节点返回数据。
我们知道DNS的目的就是通过域名去获得IP地址。
但这只是它的众多功能之一。
DNS消息有很多种类型,其中A类型,就是用域名去查域名对应的IP地址。而CNAME类型,则是用域名去查这个域名的别名,然后再查一次才能得到对应的IP地址。
对于普通域名,DNS解析后一般就能直接得到域名对应的IP 地址(又叫A类型记录
,A指Address)。
为什么要加个CNAME那么麻烦?
CNAME里指向的,其实是CDN专用的DNS域名服务器,它对整个DNS体系来说,只是其中一台小小的DNS域名服务器,看起来就跟其他域名服务器一样,平平无奇。DNS请求也会正常打入这个服务器里。
但当请求真正打到它上面的时候,它的特别之处就体现出来了,当查询请求打入域名服务器时,普通的DNS域名服务器返回域名对应的部分IP就够了,但CDN专用的DNS域名服务器却会要求返回离调用方"最近的"服务器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的两倍。
但看到这里,问题又又来了。
上面的截图里,红框里有个词叫"回源"。
回源是什么?
当我们访问https://cdn域名/图片地址.png
时,请求会打到cdn服务器上面。
但cdn服务器本质上就是一层缓存,并不是数据源,对象存储才是数据源。
第一次访问cdn获取某张图片时,大概率在cdn里并没有这张图片的数据,因此需要回到数据源那去取出这份图片数据。然后再放到cdn上。下次再次访问cdn时,只要缓存不过期,就能命中缓存直接返回,这就不需要再回源。
于是访问的过程就变成了下面这样。
那还有哪些情况会发生回源呢?
除了上面提到的cdn上拿不到数据会回源外,还有cdn上的缓存过期失效了也会导致回源。
另外,就算有缓存,且缓存不过期,也可以通过cdn提供的开放接口来触发主动回源,但这个我们比较少机会能接触到。
另外,回源这个事情,其实用户是感知不到的,因为用户去读图片的时候,只能知道自己读到了还是读不到。
同样是读到了,还细分为是从cdn那直接读的,还是cdn回源读对象存储之后返回的。
那么,我们有办法判断是否发生过回源吗?
以阿某云为例,当我们请求图片时,返回结果里有个叫X-Cache
的Resp Header
信息,当它为TCP-Miss
时是未命中缓存导致CDN回源,查OSS拿到数据后返回。
当它为TCP-Memory-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获取图片的时候,CDN节点上大概率没有你要的数据,相当于每次都需要回源到对象存储去取一把。那接入CDN相当于给自己加了一层代理,多一层代理,就多一层耗时。
小结
-
对于那些小清新的文本数据,MySQL就像个稳重的老爸,默默无闻地把一切都收在自己庞大的数据库里。而Redis呢,它就是那个机灵鬼儿子,负责在前端和老爸之间传递消息,确保热乎的数据能快速送到用户手里。
-
但是,当数据变成了一大堆视频和图片,就像是你家突然变成了电影资料馆和美术馆的结合体,这时候就不能光靠老爹和儿子了。这时候,OSS(对象存储服务) 登场了,它就像是个超级大的云盘,专门用来存放这些大块头文件。至于CDN,它更像是个全球快递小哥,无论用户在哪,都能迅速找到最近的网点,把数据“嗖”地一声送过去!
-
不过,这位快递小哥也有点儿小毛病,那就是万一它得回家拿东西(也就是回源),那速度可就比平时慢多了,毕竟谁愿意多走冤枉路呢?
-
CDN真正的牛逼之处,在于它能让全世界的用户都享受到本地服务的速度感,尤其是当你一遍又一遍地请求同一份文件时,它就像个记性超好的朋友,记得你上次要的东西,下次直接从口袋里掏出来给你。但如果你们家的文件都是独一无二的艺术品,而且 藏在家里(内网) 不轻易示人,那这位快递小哥也就没啥用武之地了,毕竟他擅长的是在外面跑来跑去,而不是在家门口打转。
-
所以,用不用CDN,还得看你的用户是不是满世界飞,以及你的文件是不是那种看了还想再看的类型哦!