16 | CDN:静态资源如何加速?

前面了解了缓存的定义以及常用缓存的使用姿势,你应该对包括本地缓存、分布式缓存等缓存组件的适用场景和使用技巧有一定了解。你会将单个缓存节点扩展成高可用的缓存集群。现在,你的电商系统架构演变成了这样:


image.png

在这个架构中我们使用分布式缓存对动态请求数据的读取做了加速,但 是在我们的系统中存在着大量的静态资源请求:
1.对于移动APP来说,这些静态资源主要是图片、视频和流媒体信息;
2.对于web网站来说,则包括了js文件,css文件、静态HTML文件等。

商品的图片、介绍商品的使用方法的视频等等静态资源都放在了Nginx等web服务器上。它们的请求量极大,并且对访问速度的要求很高还占据了很高的带宽,这时会出现访问速度慢带宽被占满影响动态请求的问题,那么就需要考虑如何针对这些静态资源进行读加速了。

静态资源加速的考虑点

我们是否也可以使用分布式缓存来解决这个问题?答案是否定的,一般来说,图片和视频的大小会在几M到几百M之间不等,如果我们的应用服务器和分布式缓存都部署在北京的机房里,这时一个杭州的用户需要访问缓存中的一个视频,那么这个视频文件就需要从北京传输到杭州,期间会经过多个人公网骨干网络,延迟很高,会让用户觉得视频打开很慢,严重影响体验。

所以静态资源访问的关键点是就近访问。即北京的用户访问北京的数据,杭州的用户访问杭州的数据,这样才可以达到性能的最优。
用户遍布子全国各地,有些应用可能还有国外的用户,我们不可能在每个地域都自建机房,成本太高。

静态资源很大访问量又极高,如果使用业务服务器和分布式缓存来承担这些流量,无论是内网还是外网的带宽都会是很大的考验。

所以我们考虑在业务服务器的上层增加一层特殊的缓存,用来承担绝大部分对于静态资源的访问,这一层特殊的缓存节点需要遍布在全国各地,这样可以让用户选择最近的节点访问。缓存的命中率也需要一定的保证,尽量减少访问资源存储源站的请求数量(回源请求)。这一层就是CDN。

CDN的关键技术

CDN(内容分发网络)。简单来说,CDN就是讲静态的资源分发到位于多个地理位置机房中的服务器上,因此它能很好地解决数据就近访问的问题,加快了静态资源的访问速度。

在大中型公司里面,CDN的应用非常的普遍,大公司为了提供稳定的CDN服务会选择自建CDN,而大部分公司基于成本还是会选择专业的CDN厂商,阿里云,蓝汛,网宿的。

对于CDN来说,你可能了解它的作用。但是当让你来配置CDN或者排查CDN方面的问题时,就可能因为不了解它的原理而束手无策了。

**搭建一个CDN系统需要考虑两点:
1.如何将用户的请求映射到CDN节点上;
2.如何根据用户 地理位置信息选择比较近的节点。

如何让用户的请求到达CDN节点

首先我们考虑一如何让用户的请求到达CDN节点,你可能会觉得只需要告诉用户CDN节点的IP地址,然后请求这个IP上部署的CDN服务就可以了。但是这样会有一个问题:我们使用的是第三方厂商的CDN服务,如果这个节点的IP发生了了变更咋办?或者说我们更改了CDN厂商怎么办?是不是要修改所有的商品url域名呢?所以,**我们要做的事情就是将第三方提供的IP隐藏起来,给到用户的最好是一个本公司域名的子域名。

如何做到这一点?需要依靠DNS来帮我们解决域名映射的问题。

DNS(域名系统),实际上就是一个存储域名和ip地址对应关系的分布式数据库。而域名解析的结果一般有两种,一种叫做“A记录”,返回的是域名对应的IP地址;另一种是“CNAME记录”,返回的是另一个域名,也就是说当前域名的解析要跳转到另一个域名的解析上。实际上www.baidu.com域名的解析结果就是一个CNAME记录,域名的解析被跳转到www.a.shifen.com了,我们正是利用CNAME记录来解决域名映射的问题。

具体如何解决的呢?

比如你的公司的一级域名叫做example.com,那么你可以给你的图片服务的域名定义为“img.example.com”,然后将这个域名的解析结果的CNAME配置到CDN提供的域名上,比如uclound可能会提供一个域名是“80f32f92.cdn.ucloud.com.cn”这个域名。这样你的电商系统使用的图片地址可以是“img.example.com/1.jpg”。

用户在请求这个地址时,DNS服务器会将域名解析到80f32f92.cdn.ucloud.com.cn域名上,然后再将这个域名解析为cdn的节点IP,这样就可以得到CDN上面的资源数据了。

不过这里存在一个问题:因为域名解析的过程是分级的,每一级专门的域名服务器承担解析的职责,所以域名的解析过程可能需要跨越公网做多次DNS查询,性能上是比较差的

image.png

从中可以看出DNS分为很多种,有根DNS,顶级DNS等,除此之外还有两种DNS需要特别留意:一种是Local DNS,它是由你的运营商提供的DNS,一般域名解析的第一站会到这里;另一种是权威DNS,它的含义是自身DB中存储了这个域名对应关系的DNS。

下面以www.baidu.com为例简单介绍一下域名的解析过程:

  • 一开始,又没给你解析请求先会检查本机的hosts文件,查看是否有www.baidu.com对应的IP;
  • 如果没有,就请求Local DNS是否有域名解析结果的缓存,如果有就返回标识是从非权威DNS返回的结果;
  • 如果没有就开始DNS的迭代查询。先请求根DNS,根DNS返回顶级DNS(.com)的地址;再请求.com顶级dns得到baidu.com的户名服务器地址;再从baidu.com的域名服务器中查询到www.baidu.com对应的IP地址,返回这个IP地址的同时交际这个结果是来自于权威DNS的结果,同时写入Local DNS的解析结果缓存,这样下一次解析同一个域名就不需要做DNS的迭代查询了。
    经过了向多个DNS服务器做查询之后,整个DNS的解析的时间有可能回到秒级别。那么如何来解决这个性能问题呢?

一个解决的思路是:在APP启动时对需要的解析的域名做预先解析,然后把解析的结果缓存到本地的一个LRU缓存里面。这样当我们要使用这个域名的时候,只需要从缓存中直接拿到所需要的IP地址就好了,如果缓存中不存在才会走整个dns查询的过程。同时为避免dns解析结果的变更造成缓存内数据失效,我们可以使用定时器定期更新缓存中的数据。

经过测试,对于HTTP请求的响应时间提升很明显。 原先DNS解析时间经常会超过1s,使用这种方式后,DNS解析时间可以控制在200ms以内,整个http请求的过程可以减少大概80-100ms。

image.png

总结一下,将用户的请求映射到cdn服务器上是使用cdn时需要解决的一个核心的问题,而CNAME记录在DNS解析过程中可以充当一个中间代理层的角色,可以把将用户最初的域名代理到正确的IP地址上。

image.png

那么如何找到更近的CDN节点?GSLB承担了这个责任

如何找到离用户最近的CDN节点

GSLB(全局负载均衡)的含是对于部署在不同地域的服务器之间做负载均衡,下面可能管理了很多本地的负载均衡组件。它有两方面作用。

  • 它是一种负载均衡服务器,负载均衡,指的是让流量平均分配使得下面管理的服务器的负载更平均;
  • 另一方面它需要保证流量流经的服务器与流量源头在地缘上是比较接近的。

有了GSLB之后,节点的解析过程变成了下图中的样子:


image.png

当然,是否能够从CDN节点上获取到资源还取决于CDN的同步延时。一般我们会通过cdn厂商的接口将静态的资源写入到某一个CDN节点上,再由CDN内部的同步机制将资源同步分散到每个CDN节点,即使CDN内部网络经过了优化,这个同步的过程是有延迟的,一旦我们无法从选定的CDN节点上获取到数据,我们就不得不从源站获取数据,而用户网络到源站的网络可能会跨越多个主干网,这样不仅性能上有损耗也会消耗源站的带宽,带来更高的研发成本。所以我们在使用CDN的时候需要关注CDN的命中率和源站的带宽情况。

你可能感兴趣的:(16 | CDN:静态资源如何加速?)