聊聊 CDN 缓存与浏览器缓存

avatar
运维 @又拍云

CDN 是互联网上内容分发的重要一环。无论您之前是否了解过 CDN,其实它已经在您的日常生活中发挥作用了。比如您正在淘宝挑选心仪的商品,或者在观看一段令人捧腹的视频,以及您正在阅读的这篇文章,这些资源展示的背后都有 CDN 的默默支撑。

为什么 CDN 使用如此广泛呢?首先大家需要知道,CDN 旨在解决的最重要的问题是什么,我们称之为网络延迟。举个例子,当您输入一个网址,敲击回车后到网页内容实际出现在屏幕上,中间加载耗费的这个时间,就是网络延迟。通过网络获取资源总是比从本地获取慢,无论服务器是在同一个局域网中还是位于世界的另一个角落,都是如此。这里的速度差异是 IT 行业的一个核心问题,开发者想了很多办法试图去弥补这个差异,CDN 就是应用最为广泛的一个解决方案。

CDN 为解决网络延迟提供了一整套技术方案,今天我们介绍的缓存就是其中重要的一环。这篇文章主要介绍在使用了 CDN 之后,数据是如何被缓存的,以及缓存是如何提高数据加载速度的。

缓存的优点

在未接入CDN 之前,用户使用浏览器访问服务的时候,相互交互的过程如下图所示。

用户在第一次访问网站服务器的时候,浏览器会从服务器获取所有的资源,在传输过程中,浏览器会通过一些约定好的响应头,从而确定是否需要将这个资源保存一份到本地作为缓存。当用户第二次访问该网站的时候,浏览器就会优先从缓存中加载资源,不用向服务器请求资源,从而提高了网站的访问速度。

例如我们第一次访问又拍云官网,下面就是浏览器加载资源的快照,可以看到 5.6MB 的数据被传输到本地。

在刷新又拍云官网后,我们可以看到传输数据降到了 9.9KB,在使用了缓存之后,浏览器不用再下载全部的文件,减少了下载量也就意味着提高了页面加载的速度。

通过上面的例子,可以直观地观察到浏览器缓存对解决网络延迟起到的作用是非常明显的。

而对于一些用户访问量巨大的网站而言,如果所有用户都去服务器请求数据,服务器会很快崩溃,并且在不同网络以及不同地区的用户,请求服务器的速度也不一样。为了提高这部分用户的访问速度,CDN 中又提出了新的网络架构,即创建一些最接近用户网络的边缘服务器,然后将文件缓存在这些边缘服务器(节点)上,这就是 CDN 缓存。

大家可以看到,服务接入了 CDN 后,数据经历了客户端(浏览器)缓存和 CDN 边缘节点缓存两个阶段,那么下面就分别对这两个阶段的缓存进行介绍。

浏览器缓存介绍

当我们请求一个网页的时候,服务器会向浏览器返回大量数据,但是这些数据需要全部缓存吗?浏览器又是如何区分哪些数据需要进行缓存,哪些是需要实时跟源站获取的?接下来我们就来看一下浏览器的缓存策略。

浏览器缓存策略

服务器会在资源返回的响应中,携带上以下四个常用的响应头,浏览器会通过判别这些响应值来决定资源缓存的状态。

  • ETag
  • Cache-Control
  • Expires
  • Last-Modified

ETag

ETag 值是一个字符串,其内容通常是数据的哈希值,每个数据都有一个单独的标志,只要这个文件发生了改变,这个标志就会发生变化。

服务器可以在响应中返回 ETag,然后浏览器会在后续的请求中携带上这个参数来确定缓存是否需要更新。如果 ETag 值相同,说明资源未更改,服务器会返回 304(Not Modified) 响应码,浏览器就知道本地缓存仍然是可以使用的。

不过需要注意的是,ETag 只有在本地缓存已过期(Expires)或者缓存模式设置为 no-cache(Cache-Control)的时候,才会被浏览器携带上与服务器端的值进行判别。

Cache-Control

Cache-Control 可以携带多个响应值,这些值可以设置缓存时间、状态以及验证状态。不同值说明如下。

例如,访问某张图片,服务器返回的响应如下:Cache-Control: max-age=691200,则说明这张图片可以在客户端存储 8 天。

Expires

这个响应头标记了数据的过期时间,超过其中规定的时间后,缓存会被定义为过期。例如:Expires: Sat, 27 Apr 2019 11:43:15 GMT

说明对应的数据会在 2019 年 4 月 27 号的 11 点 43 分后过期。

需要注意的是,如果 Cache-Control 中有 max-age 指令,浏览器会忽略此参数。

Last-Modified

服务器可以通过配置这个响应头,来向浏览器发送一个数据上次被修改的时间标签,例如:Last-Modified:Wed, 24 Apr 2019 02:54:16 GMT

这样浏览器就知道了该数据最后被修改的时间,后续请求中,会和服务器进行时间的比较,如果服务器上的时间比本地时间要新,说明数据有更改,浏览器需要重新下载数据。

HTTP 响应示例

接下来我们可以看一个响应示例。

第 2 行告诉我们 max-age 是 1 小时;

第 5 行告诉我们这是一张 PNG 图片;

第 7 行向我们显示了 ETag 值,该值将在 1 小时标记后用于验证,以验证资源是否有更改;

第 8 行是 Expires 响应,因为设置了 max-age,它将被浏览器忽略;

第 10 行是 Last-Modified 响应,显示上次修改图像的时间。

浏览器缓存的不足

当服务器返回的响应中有 Expires 或者 Cache-Control 设置了 max-age 响应头的时候,浏览器不会向服务器发起校验请求,而是直接复用本地缓存。如果此时服务器进行了资源的更新,用户就无法获取到最新的资源,只能通过强制刷新浏览器缓存来跟服务器请求最新的资源。

此外,Expires 是服务器返回的一个绝对时间,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题,比如随意修改下客户端时间,就能影响缓存命中的结果。

因此在实际使用过程中,需要灵活使用浏览器的缓存策略。

CDN 缓存介绍

当服务接入了 CDN 之后,浏览器本地缓存的资源过期之后,浏览器不是直接向源服务器请求资源,而是转而向 CDN 边缘节点请求资源。CDN 边缘节点中将用户的数据缓存起来,如果 CDN 中的缓存也过期了,CDN 边缘节点会向源服务器发出回源请求,从而来获取最新资源。以下介绍以又拍云 CDN 为例。

CDN 缓存策略

CDN 节点缓存策略一般都会遵循 HTTP 标准协议,又拍云在没有匹配到自定义缓存规则且源服务器也没有返回任何有效缓存头的情况下,默认配置策略如下:

  1. 针对静态资源,所有正常状态码(大于等于 200 小于 400)均缓存 8 天。特别地,301 响应缓存 2 小时,302 响应缓存 20 分钟;
  2. 针对动态资源,程序会自动识别,则不进行缓存;
  3. 对于其他大于等于 400 的不正常响应,则不进行缓存;

缓存节点通知浏览器缓存的具体时间由 HTTP 响应头里面的 Cache-Control 和 Expires 响应头控制。

CDN 缓存的不足

CDN 缓存不仅减少了用户的访问延时,相应的也减少了源服务器的负载,但这里需要注意,当源服务器资源更新后,如果 CDN 节点上缓存数据还未过期,用户访问到的依旧是过期的缓存资源,这会导致用户最终访问出现偏差。因此,开发者需要手动刷新相关资源,使 CDN 缓存保持为最新的状态。

CDN 缓存刷新

又拍云为开发者执行缓存刷新提供了主动更新和被动更新两种方式。

主动更新主要是指同名资源在源服务器更新之后,开发者手动刷新文件。又拍云提供了可视化的操作台供用户执行缓存刷新操作,同时支持 URL 刷新和规则刷新。此外开发者也可通过 API 接口完成刷新操作。

被动刷新则是等文件在 CDN 节点的缓存过期之后,节点回源拉取源服务器上最新的文件。这个过程由 CDN 自动完成,无需手动操作。

现如今是一个快节奏的时代,人们总是希望自己能够第一时间获取到最新的资讯,使用的是最快捷的服务。又拍云一直致力于解决互联网网络拥塞问题,提高终端用户访问网站的响应速度和可用性,为广大开发者提供更加简洁方便的 CDN 一站式服务。

目前又拍云 CDN 可以提供基于文件后缀、目录等多个维度来指定 CDN 缓存和浏览器时间,为开发者提供更精细化的缓存管理服务。针对开发者不同的业务需求,又拍云提供了多项预制模板,方便快捷的来帮助开发者进行数据缓存管理,有效减轻源站负载,通过各网络、各区域的多个节点,来帮助减小终端用户访问服务延时。

推荐阅读:

这样介绍 CDN,老司机也能听懂

聊聊常见的网络攻击 - 又拍云​