CDN 回源策略与缓存规则设计:动态内容站点的加速实践

CDN 回源与缓存策略封面图

电商页面价格实时变、社区帖子列表不断更新——这类动态内容站点接入 CDN(内容分发网络)后,最常见的困惑是命中率上不去,回源请求把源站打满。这篇文章教你从回源策略和缓存规则两个维度重新设计接入方案:该缓存的坚决缓存,必须回源的高效回源,并用可复制的命令逐项验证。

先弄清楚:什么是回源,为什么它决定动态站点的速度

回源,指的是 CDN(内容分发网络)边缘节点在自己没有可用缓存(cache miss)时,向你的源站服务器发起请求取数据的过程。用户请求并不直接到达源站,而是先落在离他最近的边缘节点;节点本地命中缓存就直接返回(cache hit),未命中才回源。命中越多,用户等待越接近节点的几毫秒;回源越多,源站 CPU、数据库连接和带宽(数据传输容量)压力越大。

命中情况不用猜,CDN(内容分发网络)会在响应头给出标记:curl -sI https://example.com/style.css | grep -i cache,重点看 X-Cache: HIT/MISSAge(内容已在节点上存放的秒数)。同一 URL 连续请求两次,先 MISS 后 HIT 说明链路正常;始终 MISS 多半是响应头禁用缓存或缓存键配错。

对动态站点来说,真正的问题在于”不可缓存的内容占比高”。商品详情页的静态框架可以缓存,但价格、库存、购物车必须实时;如果缓存规则把整页 HTML 都标记为不缓存,每次访问都会触发完整回源,CDN(内容分发网络)就退化成普通反向代理,加速无从谈起。

第一步:把页面拆开,区分可缓存与不可缓存部分

设计缓存规则前先做内容盘点:打开开发者工具的 Network 面板刷新一次典型页面,把请求按变化频率分成三类——几乎不变的(JS、CSS、字体)、分钟级变化的(商品图片、分类页 HTML)、每次都变的(购物车、个性化推荐、登录态)。这个分类决定了每类资源的缓存 TTL(缓存生存时间)。

静态资源规则最容易定:Cache-Control: public, max-age=31536000, immutable 配合带版本号的文件名(如 app.a3f9c2.js),一年不过期,更新靠换文件名,发布时只有文件名变化的资源回源。仅这一条通常就能把命中率从 40% 拉到 80% 以上——按请求数算,静态资源往往占一个页面的八成。

半动态内容是提升空间最大的部分,常用的做法有两个。其一是”短 TTL + 主动刷新”:分类页 HTML 缓存 60-300 秒,后台改价后调用 CDN 的缓存刷新 API 精准清除对应 URL,让缓存失效由业务事件驱动而不是被动等待过期。其二是把页面拆成模板与数据接口:HTML 模板长缓存,价格库存这类实时数据走 XHR 请求回源,页面主体仍然秒开。SKU 数量巨大、刷新配额吃紧的站点更适合模板与数据分离。

对于每一次都必须回源的接口,规则同样重要:Cache-Control: private, no-store 明确告诉所有中间层不要缓存,避免出现”购物车串号”这类严重事故。漏配 private 的后果很实际:曾有站点把登录用户的昵称缓存在共享缓存里返回给其他访客,这类事故在接入后才暴露,排查成本远高于事前配置。关于把缓存分层到浏览器、应用与数据库的完整思路,可以参考这篇多级缓存架构落地指南

三类内容缓存规则设计示意图

第二步:回源方式怎么选,协议回源与回源跟随

缓存规则解决”哪些请求不必回源”,回源策略解决”必须回源的请求怎么走得更稳”。这里有几个关键决策。

第一个决策是协议回源。CDN(内容分发网络)回源时用 HTTP 还是 HTTPS,取决于源站的能力:源站已部署 SSL(安全传输协议)证书时,开启”协议跟随回源”,用户 HTTPS 访问则节点 HTTPS 回源,全链路加密;源站没有证书时只能 HTTP 回源:用户到节点一段仍加密,但节点到源站是明文,存在被嗅探的风险。生产环境我们建议源站直接部署免费证书(例如 Let’s Encrypt,90 天有效期,可用 Certbot 自动续期),开启全链路 HTTPS 回源。

第二个决策是回源跟随。开启”回源跟随 301/302″后,节点会在边缘直接处理源站返回的重定向,而不是把 302 丢给用户再发起第二次请求。典型场景是源站做 HTTP 跳 HTTPS:不开启时每个请求多一次往返,开启后节点自己跳转并缓存最终结果。验证用 curl -sI http://example.com/path,返回 302 且 Location 指向同一域名时就该开启。

回源 Host(回源主机头)是第三个容易踩坑的点。回源 Host 默认是加速域名本身,但源站如果是 Nginx 虚拟主机或对象存储 Bucket,就必须显式改成源站实际识别的 Host,否则可能返回 404 或默认页,排查时在源站抓包确认 Host 头即可。如果你的源站前面还有一层 Nginx 反向代理,回源 Host 与 proxy_pass 的配合细节可以参考Nginx 反代缓存失效策略这篇教程。

第三步:控制回源并发,防住缓存过期瞬间的回源风暴

动态站点最危险的时刻是热门内容缓存过期瞬间:一个缓存 60 秒的分类页过期那一秒涌入 3000 个请求,没有并发控制时会被全部转发到源站——这就是回源风暴,也是”接了 CDN 反而更慢”的直接原因。

解决方案叫请求合并,多数服务商称作”缓存合并回源”或 request coalescing:同一 URL 的并发回源请求在边缘被合并成一个,第一个请求回源拿结果,其余请求等待后共享同一份结果。开启后,上面场景中真正到达源站的请求只有 1 个。这个开关在动态站点上属于必开项,效果立竿见影。

即便有请求合并,源站也要做第二层保护:Nginx 用 limit_req 限速,例如 limit_req_zone $binary_remote_addr zone=origin:10m rate=100r/s; 配合 limit_req zone=origin burst=200 nodelay;,把超出承载的请求挡在应用之前。zone 分区、burst 语义等细节见Nginx 限流配置实战。应用层面则给数据库连接池设上限(如 200),并在缓存重建路径加互斥锁,让同一时刻只有一个请求回源重建——这与多级缓存下的 Cache Stampede 应对讲的是同一类问题,只是发生位置从应用缓存挪到了 CDN 边缘。

回源风暴与请求合并对比图

观察回源量是否健康,看两个指标:回源率(回源请求数 / 总请求数)与源站 QPS 曲线。回源率稳定在 20% 以下、源站 QPS 无周期性尖刺,说明缓存规则与并发控制生效;如果每次整点出现同步尖刺,多半是大量内容被设置了相同的 TTL 同时过期——把 TTL 加上随机偏移(如 300 秒基础值 ± 60 秒抖动)即可打散。

第四步:上线前验证与持续监控

上线前跑一遍验证清单,确认每类资源的实际行为与设计一致:

  • 静态资源:连续两次 curl -sI 同一 URL,第二次应返回 X-Cache: HITCache-Control 中 max-age 与规划值一致。
  • 私有接口:登录态下请求购物车接口,响应头应为 private, no-store,且 Age 不存在或为 0。
  • 半动态页面:修改内容并触发刷新 API 后,60 秒内再次请求应返回新内容。
  • 回源链路:源站访问日志中,回源请求的 Host 头与协议与规划一致,没有出现 404 或默认页。

监控层建议同时盯三处:CDN 侧的命中率与回源率、源站的 QPS 与 P95 延迟、核心接口的报错率。命中率下降 5 个百分点往往意味着某条规则被误改,越早发现回滚成本越低。WordPress 站点还应注意插件输出对缓存头的影响,可参考WordPress 网站加速全攻略服务器配置一节核对源站响应头。

总结:一套可以复用的设计顺序

整个流程可以压缩成四步:先盘点内容分类请求,再为每类资源定缓存规则,然后为必须回源的请求选合适的回源方式,最后用并发控制与监控守住源站。核心原则一句话:缓存规则跟着内容变化频率走,回源策略跟着源站承载能力走。

建议先从回源率看板拿到基线,每次只改一类资源的缓存规则并观察一周,避免大改导致问题无法定位。如果你在挑选或升级源站,可结合业务量评估主机形态:VPS(虚拟专用服务器)方案适合中小型动态站点,业务量更大的站点可查看独立服务器的配置选项,Hostease 技术支持也可协助核对回源配置。

发表评论