CDN缓存那些事儿

8年前,还没有火车票代售点一说,12306.cn更是无从说起。那时候火车票还只能在火车站的售票大厅购买,而我所住的小县城并不通火车,火车票都要去市里的火车站购买,而从县城到市里,来回就是4个小时车程,简直就是浪费生命。后来就好了,小县城里出现了火车票代售点,可以直接在代售点购买火车,方便了不少,全市人民再也不用在一个点苦逼的排队买票了。

CDN就可以理解为分布在每个县城的火车票代售点,用户在浏览网站的时候,CDN会选择一个离用户最近的CDN边缘节点来响应用户的请求,这样海南移动用户的请求就不会千里迢迢跑到北京电信机房的服务器(假设源站部署在北京电信机房)上了。

CDN的背景与概念

从网络层面看,一个网站的体验好坏主要以下几个方面(这里只单独介绍网络环境对网站的体验好坏,一个网站的体验好坏除了网络层面还有很多的影响因素):

(1)网站服务器接入互联网的链路所能提供的带宽(出口带宽),这个带宽决定了用户的并发量和访问时延,用户越多,对出口带宽的要求就越高,当用户的并发量超过了带宽,就会导致出口网络拥塞,严重的影响用户的体验。

(2)不同运营商之间的互联问题,一般来说两个运营商之间只有两三个点是互通的,所有跨运营商之间的交互都要经过这几个点,可以想象一个使用电信的用户去访问部署在联通的网站,速度是有多么慢。

(3)长途骨干传输问题,从网站服务器到用户之间要经过网站所在的IDC、骨干网、用户所在城域网、用户所在的接入网等,物理距离非常远,导致传输时延非常高。

CDN(Content Delivery Network,内容分发网络)就是为了解决上述的问题而生的,其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络”边缘”,使用户可以就近取得所需的内容,解决Internet网络拥塞状况,提高用户访问网站的响应速度。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因,解决用户访问网站的响应速度慢的根本原因。

CDN的优势很明显:
(1)CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低;
(2)大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源站的负载。

CDN工作原理

1、传统访问过程(未使用CDN)

1
[RootDNS] <-----> [LocalDNS] <--------> [授权DNS]
                           |
                           |
                           |
                      [用户客户端]<--------> [站点服务器]

  • 1) 用户输入访问的域名,操作系统向 LocalDns 查询域名的ip地址.
  • 2) LocalDns向 ROOT DNS 查询域名的授权服务器(这里假设LocalDns缓存过期)
  • 3) ROOT DNS将域名授权dns记录回应给 LocalDns
  • 4) LocalDns得到域名的授权dns记录后,继续向域名授权dns查询域名的ip地址
  • 5) 域名授权dns 查询域名记录后,回应给 LocalDns
  • 6) LocalDns 将得到的域名ip地址,回应给 用户端
  • 7) 用户得到域名ip地址后,访问站点服务器
  • 8) 站点服务器应答请求,将内容返回给客户端

2、使用CDN后的访问过程

1
[RootDNS] <-----> [LocalDNS] <--------> [授权DNS]
                           |   \
                           |    \---\
                           |         \ 
                           |          \---\      
                           |               \[CDN智能DNS]
                      [用户客户端]<---------->[CDN节点]<-------->[站点服务器]
  • 1) 用户输入访问的域名,操作系统向 LocalDns 查询域名的ip地址.
  • 2) LocalDns向 ROOT DNS 查询域名的授权服务器(这里假设LocalDns缓存过期)
  • 3) ROOT DNS将域名授权dns记录回应给 LocalDns
  • 4) LocalDns得到域名的授权dns记录后,继续向域名授权dns查询域名的ip地址
  • 5) 域名授权dns 查询域名记录后(一般是CNAME),回应给 LocalDns
  • 6) LocalDns 得到域名记录后,向CDN智能DNS查询域名的ip地址
  • 7) CDN智能DNS 根据一定的算法和策略(比如静态拓扑,容量等),将最适合的CDN节点ip地址回应给 LocalDns
  • 8) LocalDns 将得到的域名ip地址,回应给 用户端
  • 9) 用户得到域名ip地址后,访问CDN节点服务器
  • 10) CDN节点服务器判断本地缓存是否失效,如果缓存失效则访问站点服务器,重新拉去内容,并缓存在本地备用
  • 11) CDN节点服务器应答请求,将内容返回给客户端

CDN关键技术

对比可以看出,CDN将用户的请求路由到CDN节点上;将源站点的数据拉取到CDN节点上,并做缓存等,实现了对用户站点的加速,那么CDN如何实现这些功能点,CDN主要利用了四大关键技术(内容路由技术、内容分发技术、内容存储技术、内容管理技术)来实现。

1、内容路由
内容路由功能是由CDN负载均衡系统来实现的。它的作用是将用户的请求导向整个CDN网络中的最佳节点,最佳节点可以是最近节点,延时最低节点等等,负载均衡的准确性和效率直接决定了整个CDN的效率和性能。
通常负载均衡可以分为两个层次:全局负载均衡(GSLB)本地负载均衡(SLB)。全局负载均衡(GSLB)主要的目的是在整个网络范围内将用户的请求定向到最近的节点(或者区域)。本地负载均衡(SLB)一般局限于一定的区域范围内,其目标是在特定的区域范围内寻找一台最适合的节点提供服务,因此,CDN节点的健康性、负载情况、支持的媒体格式等运行状态是本地负载均衡进行决策的主要依据。

2、内容分发
内容分发是指将内容从源站发送到CDN边缘的Cache的过程。目前主要有两种主流的内容分发技术:PUSH(分发)、PULL(回源)

PUSH(分发)是一种 主动 分发的技术。通常,PUSH 由内容管理系统发起,将内容从源或者中心媒体资源库分发到各边缘的Cache节点。分发的协议可以采用 HTTP/FTP等。通过PUSH分发的内容一般是比较热点的内容,这些内容通过PUSH方式预分发(Preload)到边缘Cache,可以实现有针对的内容提供。对于PUSH分发需要考虑的主要问题是分发策略,即在什么时候分发什么内容。一般来说,内容分发可以由CP(内容提供商)或者CDN内容管理员人工确定,也可以通过智能的方式决定,即所谓的智能分发。它根据用户访问的统计信息,以及预定义的内容分发的规则,确定内容分发的过程。

PULL(回源)是一种 被动 的分发技术,PULL分发通常由用户请求驱动。当用户请求的内容在本地的边缘Cache上不存在(未命中)时,Cache启动PULL方法从内容源或者其他CDN节点实时获取内容。在PULL方式下,内容的分发是按需的。

3、内容存储

对于CDN系统而言,需要考虑两个方面的内容存储问题。一个是内容源的存储,一个是内容在Cache节点中的存储。

对于内容源的存储,由于内容的规模比较大(通常可以达到几个甚至几十个TB),而且内容的吞吐量较大,因此,通常采用海量存储架构。

对于在Cache节点中的存储,是Cache设计的一个关键问题。需要考虑的因素包括功能和性能两个方面:在功能上包括对各种内容格式的支持、对部分缓存的支持,在性能上包括支持的容量、多文件吞吐率、可靠性、稳定性。

4、内容管理

内容管理在广义上涵盖了从内容的发布、注入、分发、调整、传递等一系列过程。在这里,内容管理重点强调内容进入Cache点后的内容管理,我们称为本地内容管理。

本地内容管理主要针对一个CDN节点(由多个CDN Cache设备和一个SLB设备构成)进行。本地内容管理的主要目标是提高内容服务的效率,提高本地节点的存储利用率。通过本地内容管理,可以在CDN节点实现基于内容感知的调度,通过内容感知的调度,可以避免将用户重定向到没有该内容的Cache设备上,从而提高负载均衡的效率。通过本地内容管理还可以有效地实现在CDN节点内容的存储共享,提高存储空间的利用率。

CDN的使用

目前CDN技术的使用主要是在静态加速、动态加速、流媒体等几个方面:

(1)静态加速:最传统的CDN加速服务,加速的对象一般是静态文件,如html、flash动画、css、js文件等,加速就是将静态文件放到CDN节点(PULL或PUSH),并缓存;用户通过CDN访问就近或最快的CDN节点获取文件。

(2)动态加速:动态加速的对象是动态声称的网页,动态加速一般是对针对内容(如数据库信息等)在用户与源站之间建立高速通道,通过路由优化、TCP加速等技术手段对动态内容进行加速,降低节点到源站之间的时延,从而大大降低了用户访问动态网页的延迟。

(3)流媒体加速:流媒体加速的对象主要是点播、直播类的服务,主要是利用CDN与P2P技术以及TCP协议优化技术来完成

缓存是什么?

有了CDN后,数据是如何被缓存的呢?缓存是一个到处都存在的用空间换时间的例子。通过使用多余的空间,我们能够获取更快的速度。

首先,看看没有网站没有接入CDN时,用户浏览器与服务器是如何交互的:

1
用户在浏览网站的时候,浏览器能够在本地保存网站中的图片或者其他文件的副本,这样用户再次访问该网站的时候,浏览器就不用再下载全部的文件,减少了下载量意味着提高了页面加载的速度。

如果中间加上一层CDN,那么用户浏览器与服务器的交互如下:

1
客户端浏览器先检查是否有本地缓存是否过期,如果过期,则向CDN边缘节点发起请求,CDN边缘节点会检测用户请求数据的缓存是否过期,如果没有过期,则直接响应用户请求,此时一个完成http请求结束;如果数据已经过期,那么CDN还需要向源站发出回源请求(back to the source request),来拉取最新的数据。

可以看到,在存在CDN的场景下,数据经历了客户端(浏览器)缓存CDN边缘节点缓存两个阶段,下面分别对这两个阶段的缓存进行详细的剖析。

浏览器缓存策略

客户端缓存减少了的服务器请求,避免了文件重复加载,显著地提升了用户地方。但是当网站发生了更新的时候(如替换了css、js以及图片文件),浏览器本地仍保存着旧版本的文件,从而导致无法预料后果。

浏览器如何来确定使用本地文件还是使用服务器上的新文件?下面来介绍几种判断的方法。

1) Expires

1
2
Response Headers
Expires:Sat, 24 Jan 2015 20:30:54 GMT

如果http响应报文中设置了Expires,在Expires过期之前,我们就避免了和服务器之间的连接。此时,浏览器无需向浏览器发出请求,只需要自己判断手中的材料是否过期就可以了,完全不需要增加服务器的负担。

2) Cache-control: max-age
Expires的方法很好,但是我们每次都得算一个精确的时间。max-age 标签可以让我们更加容易的处理过期时间。我们只需要说,这份资料你只能用一个星期就可以了。

Max-age 使用秒来计量,如:

1
Cache-Control:max-age=645672

指定页面645672秒(7.47天)后过期。

3)Last-Modified

服务器为了通知浏览器当前文件的版本,会发送一个上次修改时间的标签,例如:

1
Last-Modified:Tue, 06 Jan 2015 08:26:32 GMT

这样浏览器就知道他收到的这个文件创建时间,在后续的请求中,浏览器会按照下面的规则进行验证:

  1. 浏览器:Hey,我需要jquery.min.js这个文件,如果是在 Tue, 06 Jan 2015 08:26:32 GMT 之后修改过的,请发给我。
  2. 服务器:(检查文件的修改时间)
  3. 服务器:Hey,这个文件在那个时间之后没有被修改过,你已经有最新的版本了。
  4. 浏览器:太好了,那我就显示给用户了。

在这种情况下,服务器仅仅返回了一个304的响应头,减少了响应的数据量,提高了响应的速度。关于304响应,请参考:
https://www.cnblogs.com/ziyunfei/archive/2012/11/17/2772729.html
下图是按F5刷新页面后,页面返回304响应头。

4)ETag

通常情况下,通过修改时间来比较文件是可行的。但是在一些特殊情况,例如服务器的时钟发生了错误,服务器时钟进行修改,夏时制DST到来后服务器时间没有及时更新,这些都会引起通过修改时间比较文件版本的问题。

ETag可以用来解决这种问题。ETag是一个文件的唯一标志符。就像一个哈希或者指纹,每个文件都有一个单独的标志,只要这个文件发生了改变,这个标志就会发生变化。

服务器返回ETag标签:

1
ETag:"39001d-1762a-50bf790757e00"

接下来的访问顺序如下所示:

  1. 浏览器:Hey,我需要jquery.min.js这个文件,有没有不匹配”39001d-1762a-50bf790757e00”这个串的
  2. 服务器:(检查ETag…)
  3. 服务器:Hey,我这里的版本也是”39001d-1762a-50bf790757e00”,你已经是最新的版本了
  4. 浏览器:好,那就可以使用本地缓存了

如同 Last-modified 一样,ETag 解决了文件版本比较的问题。只不过 ETag 的级别比 Last-Modified 高一些。

5) 额外的标签

缓存标签永远不会停止工作,但是有时候我们需要对已经缓存的内容进行一些控制。

  • Cache-control: public 表示缓存的版本可以被代理服务器或者其他中间服务器识别。
  • Cache-control: private 意味着这个文件对不同的用户是不同的。只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
  • Cache-control: no-cache 意味着文件的内容不应当被缓存。这在搜索或者翻页结果中非常有用,因为同样的URL,对应的内容会发生变化。
1
Cache-control:private,max-age=0,no-cache

浏览器缓存刷新

1.(重新加载)在地址栏中输入网址后按回车或点击转到按钮

浏览器以最少的请求来获取网页的数据,浏览器会对所有没有过期的内容直接使用本地缓存,从而减少了对浏览器的请求。所以,Expires,max-age标记只对这种方式有效。

2.(普通刷新)按F5或浏览器刷新按钮

浏览器会在请求中附加必要的缓存协商,但不允许浏览器直接使用本地缓存,它能够让 Last-Modified、ETag发挥效果,但是对Expires无效。

3.(强制刷新)按Ctrl+F5或按Ctrl并点击刷新按钮

这种方式就是强制刷新,总会发起一个全新的请求,不使用任何缓存。

CDN缓存

浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。

CDN缓存的缺点
CDN的分流作用不仅减少了用户的访问延时,也减少的源站的负载。但其缺点也很明显:当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。

CDN缓存策略

CDN边缘节点缓存策略因服务商不同而不同,但一般都会遵循http标准协议,通过http响应头中的Cache-control: max-age的字段来设置CDN边缘节点数据缓存时间。

当客户端向CDN节点请求数据时,CDN节点会判断缓存数据是否过期,若缓存数据并没有过期,则直接将缓存数据返回给客户端;否则,CDN节点就会向源站发出回源请求,从源站拉取最新数据,更新本地缓存,并将最新数据返回给客户端。

CDN服务商一般会提供基于文件后缀、目录多个维度来指定CDN缓存时间,为用户提供更精细化的缓存管理。

CDN缓存时间会对“回源率”产生直接的影响。若CDN缓存时间较短,CDN边缘节点上的数据会经常失效,导致频繁回源,增加了源站的负载,同时也增大的访问延时;若CDN缓存时间太长,会带来数据更新时间慢的问题。开发者需要增对特定的业务,来做特定的数据缓存时间管理。

CDN缓存刷新

CDN边缘节点对开发者是透明的,相比于浏览器Ctrl+F5的强制刷新来使浏览器本地缓存失效,开发者可以通过CDN服务商提供的“刷新缓存”接口来达到清理CDN边缘节点缓存的目的。这样开发者在更新数据后,可以使用“刷新缓存”功能来强制CDN节点上的数据缓存过期,保证客户端在访问时,拉取到最新的数据。