新用户新用户即享 DNS 与 CDN 免费套餐。立即注册

缓存清除实用指南:从缓存键到变体级精确清除

清除了缓存却还是命中?大多数时候问题出在缓存键上。本文解释 Yeap CDN 的缓存键如何构成、查询参数的几种模式,以及带与不带查询参数的 URL 清除分别会清掉什么。

"我已经清除缓存了,为什么访问还是旧内容?"这是 CDN 用户最常问的问题之一。答案几乎总是与缓存键有关:你清除的对象和用户实际命中的对象,可能并不是同一个。这篇指南从缓存键讲起,再说明 Yeap CDN 的清除操作具体会清掉什么,以及我们在后台是怎么投递清除请求的。

缓存键:边缘如何区分"同一个文件"

边缘节点缓存每个响应时,会用一个缓存键来标识它。缓存键大致由这几部分组成:

  • 主机名,例如 www.example.com;
  • 路径,例如 /assets/app.js;
  • 规范化后的查询参数,取决于你为域名选择的查询参数模式;
  • 以及按需纳入的变体维度(例如压缩编码)。

两个请求只有缓存键相同,才会命中同一份缓存。所以 /app.js?v=1 和 /app.js?v=2 默认是两份独立的缓存,这正是"版本号参数"能让浏览器和 CDN 都拿到新文件的原因。

查询参数模式

在控制台的 CDN → 域名 → 缓存 页面,可以为域名选择查询参数的处理方式。页面上还有一个缓存键预览,会实时展示当前设置下缓存键的组成:

模式行为适用场景
标准(完整)所有参数都纳入缓存键,?a=3 与 ?a=4 是两份缓存参数会影响内容的站点
忽略完全不考虑查询参数,所有参数组合命中同一份纯静态资源
排序参数按名称排序后全部纳入,?b=2&a=1 与 ?a=1&b=2 命中同一份参数顺序不固定的客户端
白名单只有指定的参数纳入缓存键只有少数参数会改变内容
黑名单排除指定参数,其余全部纳入需要忽略 utm_source 之类的跟踪参数

实际上,边缘在计算缓存键时总会先把参数解码、按名称排序、同名多值也排序,再重新编码。所以在任何保留参数的模式下,参数顺序都不会产生重复的缓存。重新编码这一步也很重要:它保证解码后值里出现的 & 或 = 不会拼出歧义,从而避免两个不同请求被映射到同一个缓存键。

一个常见的优化:营销链接经常带着各种跟踪参数,每个不同的组合都会产生一份新的缓存,命中率因此被稀释。用黑名单模式排除这些参数,命中率通常会明显改善。

清除到底清掉了什么

在缓存设置页右上角点击 清除缓存,可以选择两种方式。

清除全站缓存

清除该域名在所有边缘节点上的全部缓存对象。适合大版本发布或者不确定影响范围时使用。代价是清除之后的一段时间内,所有请求都会回源,源站压力会短暂上升。

按 URL 清除

每行输入一个完整 URL。这里的规则是理解清除行为的关键:

  • 不带查询参数,例如 https://www.example.com/list:清除这个路径下的所有查询参数变体,包括 /list、/list?page=2、/list?page=3 等。
  • 带查询参数,例如 https://www.example.com/list?page=2:只清除这一个变体,/list?page=3 仍然保留在缓存里。

带参数清除时,你输入的查询参数会按照与缓存键完全相同的规则进行规范化(同样的模式、同样的排序和编码)。因此,即使缓存时的请求是 ?b=2&a=1,你输入 ?a=1&b=2 也能精确清掉它。

这个行为是我们根据用户反馈专门做的。早期版本的清除索引只比较主机名和路径,清除 ?a=3 时会出现"清除成功但仍然命中"的情况,因为缓存键里包含查询参数而清除匹配不包含。现在清除索引的每个条目都记录了规范化后的查询参数,清除时按变体精确匹配。

边缘的清除模型本身还支持前缀、通配符和标签等匹配方式,控制台目前开放的是全站清除和按 URL 清除。

清除请求如何到达每个节点

点击确认后,控制台几乎立刻返回。这是因为清除请求不是在你的 HTTP 请求里同步投递的:

  1. 控制面把清除任务(域名和路径列表)放入一个基于 Redis 的后台队列,然后立即返回。
  2. 队列的消费者进程并行地把任务投递到该域名所在的边缘节点,失败会自动重试。
  3. 如果队列本身不可用,控制面会退回到同步投递,保证清除不会丢失。

在边缘节点上,一次完整的清除包括两部分:从清除索引里找到所有匹配的存储键,然后在缓存存储层逐出这些对象,同时清掉内存热层。为了避免多条投递通道之间相互干扰,只有在异步上下文中能够可靠完成存储逐出的那条通道会修改索引;其他通道只做"非破坏性"的匹配,清理热层,不动索引。这样无论哪条通道先到,最终都能完整清除。

如何验证

边缘响应会带上 X-Cache-Status 头。清除之后可以用 curl 检查:

curl -sI "https://www.example.com/list?page=2" | grep -i x-cache-status
# 清除后的第一次请求:X-Cache-Status: MISS
# 再请求一次:         X-Cache-Status: HIT

如果清除后仍然看到旧内容,按顺序检查:

  • 是不是浏览器缓存?边缘清除不会影响用户浏览器里已经缓存的副本,用 curl 或无痕窗口测试。
  • 输入的 URL 是否与实际请求的主机名一致?example.com 和 www.example.com 是不同的缓存。
  • 源站自己是否还在返回旧内容?清除后边缘会回源,如果源站前面还有一层缓存,它也需要刷新。

最佳实践:尽量少依赖清除

清除是一个好用的工具,但对于静态资源,最可靠的方式是让 URL 本身随内容变化:

  • 使用带内容哈希的文件名,例如 app.3f9a1c.js,并为它们设置较长的缓存时间。新版本是新 URL,不需要清除任何东西。
  • HTML 入口页设置较短的缓存时间,让它尽快引用新的资源文件。
  • 真正需要清除时,优先按 URL 清除;只有在大范围改动时才使用全站清除。

理解了缓存键,清除就不再是玄学:你清除的是哪个键,失效的就是哪个键。

在 Yeap Cloud 上构建

新用户即享 DNS 与 CDN 免费套餐。

免费注册