CDN 缓存配置

摘要

我们都知道了CDN就是以空间换时间,从离用户最近的服务器返回资源给用户,从而达到缩短资源返回时间的目的。这过程中不得不提到缓存,有缓存这个副本存在于各地的服务器上,是上述目的可以完成的前提。针对不一样的业务,不一样的资源,用户可能希望有不一样的缓存行为。例如:哪些资源需要缓存,哪些不需要;经常变动的资源希望缓存时间较短,不常变动的资源缓存时间可以更长;CDN返回资源时希望资源的响应头如何给浏览器设置缓存行为等。本文主要介绍如何配置CDN缓存功能来符合业务场景,以及CDN缓存的工作流程。

CDN缓存概述

使用CDN加速静态资源时,CDN会将源站上的资源缓存到距离客户端最近的CDN节点上。当访问该静态资源时,可直接从CDN的缓存节点上获取,有效避免通过较长的链路回源,提高资源访问效率。

在本文中,将介绍如何通过合理配置CDN缓存功能来提升终端用户访问体验。这里先给出CDN缓存工作流程,可以后面的内容介绍完毕再回过头来看这个图会更好理解。

暂时无法在飞书文档外展示此内容

缓存规则

缓存规则主要用于影响CDN的缓存行为,当收到用户请求时,CDN会根据缓存规则的优先级,由高到低依次将用户请求与缓存规则匹配。在匹配到一条规则后,CDN就会停止匹配其余的规则,以匹配到的规则为准。

如图,缓存规则有一条兜底策略,不允许删除、修改,且这条规则的优先级始终是最低的,用于确保任何文件都可以匹配到一条规则。通过后面的介绍,大家可以再回过头来看,规则匹配到的文件会被如何缓存。

匹配相关配置

  • 优先级:表示规则的优先级,数字 1 的规则优先级最高。在收到请求时,CDN按规则的优先级,从高到低尝试将请求与规则匹配。如果请求匹配了某一条规则,CDN就停止匹配其余规则。
  • 规则类型:选择一个缓存规则的类型,有三种选择:文件后缀 :缓存规则应用于指定扩展名的所有文件;目录匹配 :缓存规则应用于指定路径下的所有文件;文件全路径:缓存规则应用于那些指定的文件。
  • 规则:根据指定的规则类型,设置文件匹配条件。如果规则类型是文件后缀,可以输入一个或者多个文件扩展名如 jpg ;如果规则类型是目录匹配,可以输入一个或者多个目录路径如 /dir ;如果 规则类型文件全路径 ,可以输入一个或者多个文件路径,可以支持作为通配符,例如 **/dir/img/myfile.png**。

缓存相关配置

缓存优先策略 CDN 关联逻辑 缓存行为 缓存时长
CDN缓存 强制缓存(开) 忽略源站响应头的不缓存指示,始终缓存文件。 遵循规则中配置的 过期时间
强制缓存(关) 不忽略源站响应头的不缓存指示。未指示缓存行为时,不缓存文件。
遵循源站 补充缓存(开) 遵循源站响应头的指示。未指示缓存行为时,缓存文件。 遵循响应头指示的缓存时长。未指示缓存行为时,遵循规则中配置的 过期时间
补充缓存(关) 遵循源站响应头的指示。未指示缓存行为时,不缓存文件。 遵循响应头指示的缓存时长

强制缓存(开)

表中列出了不同配置对应的生效行为,可以看到,当设置强制缓存(开),无论源站的缓存行为如何配置,都始终对文件进行缓存。

需要注意的是,当存在以下情况下,无论缓存规则如何设置,都不会对源站响应的文件进行缓存:

  • 源站响应中 Content-Length 头的值为 0。
  • 用户请求所使用的方法既不是 GET 也不是 HEAD。
  • 源站的响应状态码不是 2xx,并且未配置状态码缓存。
  • 对于 HEAD 请求,源站响应中包含 Transfer-Encoding:chunked 响应头。

强制缓存(关)

当配置为强制缓存(关),可以理解为遵循源站设置的缓存行为,但缓存时间遵循配置的时间。为了更方便理解,详细来说就是除了下面两种情况,其他情况都会进行缓存:

  • 源站响应包含 Cache-Control: no-store 或 Cache-Control: private头部。
  • 源站响应不包含 Cache-Control 和 Expires 头部。

补充缓存(开)

当配置为遵循源站(开),可以理解为遵循源站设置的缓存行为,但如果源站没有设置缓存行为时,CDN会缓存文件。且缓存时间也优先遵循源站中的配置,若源站没有指定缓存行为则遵循配置中的缓存时间。详细来说就是除了下面两种情况,其他情况都不会进行缓存:

  • 源站响应包含 Cache-Control: max-age 或 Expires 头部。
  • 源站响应不包含 Cache-Control 和 Expires 头部。

补充缓存(关)

当配置为遵循源站(开),则一切配置都遵循源站,只有当源站配置了缓存行为,CDN才会对文件进行缓存。也就是只有源站响应包含 Cache-Control: max-age 或 Expires 头部的情况下才会缓存,且缓存时间也永远遵循源站配置。

在以下情况下,除非指定 强制缓存(开) ,CDN都不会缓存指定的文件:

  • 源站响应包含 Cache-Control: max-age = 0 头部或者包含的 Expires 头部所指示的时间早于当前时间。

回源校验

当收到用户请求时,CDN根据优先级匹配规则,根据匹配的规则会有以下某个指示:

  • 不缓存文件。此时,CDN直接向源站请求该文件。在收到文件后,CDN将该文件响应用户请求,不会缓存该文件。

  • 文件需要被缓存。此时,CDN会根据 缓存键值规则 ****检查请求是否命中了缓存。检查结果如下之一:

    • 请求命中了缓存,且缓存的文件未过期。此时,CDN将缓存中的文件响应用户请求。
    • 请求命中了缓存,但是缓存中的文件已过期。此时,CDN会进行回源 校验
    • 请求未命中缓存。此时,CDN会向源站请求该文件。在收到文件时,CDN将该文件响应用户请求,同时根据该缓存规则的指示缓存该文件。

其他过程都比较清晰,这里主要介绍一下回源校验的流程。当一个缓存文件过期后,如果收到了该文件的请求,CDN会向源站校验该文件是否有更新。回源校验的流程如下:

  • 如果该文件的源站响应包含 Last-Modified 字段或者 ETag 头部,CDN会在回源请求中包含用于文件校验的头部。ETag 的优先级高于 Last-Modified。

    • 如果源站响应包含 ETag,回源校验请求中会包含 If-None-Match 头部。该头部的值就是 ETag 的值。
    • 如果 ETag 不存在但是 Last-Modified 存在,回源校验请求中会包含 If-Modified-Since 头部。该头部的值就是 Last-Modified 的值。
  • 如果缓存文件的源站响应中既没有包含 Last-Modified,也没有包含 ETag 头部,内容分发网络就直接向源站请求该文件。在收到文件后,内容分发网络会将文件响应用户请求并缓存该文件。

  • 关于源站的响应状态码:

    • 如果状态码是 304,表示该文件在源站没有更新。此时,CDN将缓存的文件响应用户请求。
    • 如果状态码是 200,表示该文件在源站有更新并且响应正文中包含了最新的文件。此时,CDN会将更新的文件响应用户请求并在缓存中替换已有的文件。
    • 无论哪种结果,都会重置过期时间。

一个简单的例子

  1. 当没有配置缓存规则时,访问www.wymtest.com/ignorecase/smoke.jpg,在终端中输入:curl -x xxx.xxx.xxx.xxx:xxxx(这里没有注册dns,需要代理服务器) -sv www.wymtest.com/ignorecase/...

    1. 得到结果:响应头中没有Cache-Control 也没有Expires,且x-response-cache: miss。(图太长了,只截图部分)
  2. 配置缓存规则为如图

    1. 待配置生效后,再次执行curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...
    2. 这时返回的其他内容都跟第一次一样,不同的是响应头Age:2,说明这次请求后,文件被缓存了,且返回的是被缓存的文件,文件缓存时间与文件响应时间之间相差2s。
  3. 快速再次执行curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...

    1. 这时返回响应头的Age变成了6,当响应返回时,缓存已经存在6s。且x-response-cache返回edge_hit,说明直接命中缓存,并返回缓存。

缓存键值

缓存键是每个在缓存中的文件的唯一标识。在收到一个用户请求时,CDN会对请求生成一个缓存键。默认情况下,缓存键包含 Host、路径、查询参数。例如,www.example.com/image.png?version=1。然后CDN会尝试将该缓存键与缓存文件的缓存键相匹配,匹配时缓存键是大小写敏感的。

  • 如果找到一个匹配,则表示缓存命中,CDN将缓存的文件发送给用户。
  • 如果未找到匹配,则表示缓存未命中,CDN会向源站请求该文件。在收到该文件后,CDN会使用该缓存键来缓存文件。

缓存键值配置的目的就是指示CDN在对请求生成缓存键时,缓存键中包含哪些请求 URI 中的查询参数。由于生成的缓存键会被CDN用来匹配缓存的文件,因此缓存键值规则会直接影响缓存命中率。同样,缓存键值也有一条兜底策略。

参数缓存类型

参数缓存类型 行为 指定参数
保留全部参数 包含请求 URI 中全部的查询参数 该配置的值必须是 ** 表示全部查询参数。
删除全部参数 不包含任何的查询参数。
删除部分参数 包含除了指定参数以外全部的查询参数。 可以指定一个或者多个查询参数,但是不能指定 *
保留部分参数 包含指定的查询参数。

如果站点上文件 URI 中的某些查询参数并不是用来区分文件的,可以通过创建缓存键规则来指定CDN在生成的缓存键值中需要丢弃的查询参数,以提高缓存命中率,减少回源请求。

站点根目录下的文件 URI 中包含 version,token 这两个参数。这两个参数中,只有 version 是用来区分文件的。例如 /image.png?version=1/image.png?version=2 是两个不同的文件。但是 /image.png?version=1&token=abc/iamge.png?version=1&token=xyz 是相同的文件。CDN先后收到两个该文件的请求。请求的 URI 分别是 /image.png?version=1&token=12345/image.png?version=1&token=abcde

如果未配置缓存键值,在收到第一个请求时,内容分发网络缓存该文件。该文件在缓存中的缓存键是 /image.png?version=1&token=12345。在收到第二个请求时,内容分发网络会使用 /image.png?version=1&token=abcde 去匹配缓存中的文件。由于没有命中缓存,内容分发网络会向源站请求该文件。

思考:如何配置缓存键值可以使得两个请求都命中缓存。

一个简单的例子

仍然用前面的文件来实验,通过前面的配置/ignorecase/smoke.jpg这个文件已经被缓存。

  1. 执行:curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...

    1. 得到结果:未命中缓存
  2. 配置缓存键值为如图

    1. 执行:curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...
    2. 得到结果:命中缓存

状态码缓存

在回源时,如果源站的响应状态码不是 2xx,缓存节点默认不会缓存请求的内容。如果另一个用户请求相同的内容时,还是会触发回源。如果用户希望在短时间内避免这些内容的回源,可以通过配置状态码缓存来降低源站压力。在配置了状态码缓存后,在指定的时间内,如果缓存节点收到了上述情况的内容的访问请求,缓存节点不会回源,而是直接返回状态码。

一个简单的例子

  1. 我们来访问一个不存在的资源,执行:curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...

  2. 配置状态码缓存如图:

    1. 这时再次执行,结果与前两次一致,但这次执行已经对该状态码进行了缓存。当第四次执行时,就会发现已经命中缓存。
    2. 仍然404,但缓存命中。

浏览器缓存

当CDN响应一个用户请求时,除了将请求的文件发送给用户,也可以指示用户的浏览器该如何对该文件进行缓存。通过指定浏览器缓存策略,可以对特定文件在用户浏览器中的缓存行为进行设置。

浏览器缓存策略与源站响应中所指示的缓存行为有关。在向源站请求一个文件时,源站的响应头中会指示该文件的缓存行为,CDN在缓存该文件时会记录该响应头。

缓存策略

策略 行为
缓存 如果请求文件的源站响应中 Cache-Control 响应头不包含 no-cache、no-store 或者 private 指令,CDN在响应用户请求时会包含 Cache-Control: max-age=N 响应头。该响应头告知浏览器需要缓存该文件,其缓存时间 N 就是在策略中指定的缓存过期时间。
遵循源站 在响应用户请求时,CDN会包含请求文件的与缓存相关的源站响应头。
不缓存 CDN指示浏览器不要对请求的文件进行缓存。在响应用户请求时,CDN会包含 Cache-Control: no-store 响应头

一个简单的例子

还是用前面的文件,当不配置浏览器缓存时,由于将遵循源站 Cache-Control 响应头的配置,该文件源站没有设置 Cache-Control,所有响应中并没有相关头。

  1. 执行:curl -x xxx.xxx.xxx.xxx:xxxx -sv www.wymtest.com/ignorecase/...

    1. 响应中没有缓存相关头。
  2. 设置浏览器缓存如下

如何提升缓存命中率

CDN缓存命中率包括字节命中率请求命中率

  • 字节命中率=CDN缓存命中响应的字节数 ÷ CDN所有请求响应的字节数
  • 请求命中率 = CDN缓存命中的请求数÷ CDN所有的请求数

一般我们提到的CDN缓存命中率指的是请求命中率。

命中率间接反应了回源的流量的大小,命中率越低,回源的次数和流量越多,对源站的负载压力也就越大。因此提高CDN的命中率对降低源站访问压力很有必要。

合理配置缓存过期时间

缓存过期时间决定了CDN回源的频率,设置时间越长回源频率越低。

  • 更新频率低的文件

可将不常更新的资源文件比如网站的一些图片、模版示例文件、或者一些例如安装包的js、css文件的过期时间设置的长一些,建议设置1个月以上。

  • 频繁更新的文件

这类文件可以根据迭代更新频率进行设置,比如如果是两周一迭代,那么可将这类文件的缓存时长设置为14天左右。如果有突发版本低于两周发布的情况,我们也可以使用CDN提供的刷新预热功能进行处理。

预热资源

就是上面提到的刷新预热功能。一般适用于在大型活动发布前,先将发布的内容使用CDN刷新预热功能提前从源站获取资源到CDN缓存节点以提高缓存命中率。这里要注意的是预热功能有一定的限制,所以需要提前规划好资源分配。

备注:为避免刷新、预热配额滥用,每个用户的每日配额有上限限制,需要慎重使用。

配置缓存键值

前面已经详细介绍,通过缓存键值去除站点上文件 URI 中的某些不是用来区分文件的查询参数来提升缓存命中率,此处不再赘述。

大文件设置分片 回源 策略

用户可能只需要大文件的某些分片,也就是说用户的请求是Range请求,或者用户在访问大文件时时可能会中断操作。这两种情况,CDN向源站请求的都是整个完整的资源,这时回源资源内容大于响应给用户的内容,会导致缓存命中率低。

所以针对大文件,建议开启回源Range,开启后CDN在向源站发起请求时就会使用 Range 请求。有关回源Range配置将单独放在「回源配置」另外讲解。

配置共享缓存

当同一个用户的多个加速域名回相同的源站,不同的域名下,同一个url是同一份文件,可以使用一份缓存,所以可以配置域名间的共享缓存,来减少回源。共享缓存即允许多个加速域名共享同一份缓存。

当收到某个共享缓存域名的一个请求,共享缓存的工作流程如下:

  1. 根据共享缓存域名下的缓存规则,确定请求的文件是否需要被缓存以及缓存的时长。 如果文件不需要被缓存,CDN向共享缓存域名的源站请求该文件,然后使用该文件响应这个请求,流程结束。
  2. 如果文件需要被缓存,CDN会将请求的文件 URL 中的域名替换成目标域名,然后在缓存中查找请求的文件,如果在缓存中没有找到该文件,则走到第4步。
  3. 如果在缓存中找到了该文件,CDN会使用步骤1中获取的缓存时长来判断缓存的文件是否已经过期。如果文件没有过期,CDN使用该文件响应这个请求,流程结束。
  4. 如果文件已经过期或者CDN没有在缓存中找到该文件,则向共享缓存域名的源站请求该文件。
  5. 从源站获取文件后,将该文件作为目标域名的文件进行缓存,流程结束。
相关推荐
全宝1 分钟前
🖲️一行代码实现鼠标换肤
前端·css·html
小小小小宇26 分钟前
前端模拟一个setTimeout
前端
萌萌哒草头将军30 分钟前
🚀🚀🚀 不要只知道 Vite 了,可以看看 Farm ,Rust 编写的快速且一致的打包工具
前端·vue.js·react.js
芝士加1 小时前
Playwright vs MidScene:自动化工具“双雄”谁更适合你?
前端·javascript
Carlos_sam2 小时前
OpenLayers:封装一个自定义罗盘控件
前端·javascript
前端南玖3 小时前
深入Vue3响应式:手写实现reactive与ref
前端·javascript·vue.js
wordbaby3 小时前
React Router 双重加载器机制:服务端 loader 与客户端 clientLoader 完整解析
前端·react.js
itslife3 小时前
Fiber 架构
前端·react.js
3Katrina3 小时前
妈妈再也不用担心我的课设了---Vibe Coding帮你实现期末课设!
前端·后端·设计
hubber3 小时前
一次 SPA 架构下的性能优化实践
前端