CDN 服务器缓存优化

动态内容分类导致的缓存未生效现象

最近在分析游戏服务器的 API 响应速度时,发现与静态文件不同,JSON 数据无法被缓存。原因是根据 Cloudflare 的默认策略,HTML 或 JSON 等基于文本的数据被归类为动态内容。 响应头中的 CF-Cache-Status: DYNAMIC 状态意味着用户的请求绕过了 CDN,直接连接到源站(Origin Server),这最终成为了加重源站负载的因素。

https://developers.cloudflare.com/cache/concepts/default-cache-behavior Default cached file extensions "Cloudflare only caches based on file extension and not by MIME type. The Cloudflare CDN does not cache HTML or JSON by default. Additionally, by default Cloudflare caches a website's robots.txt."

sequenceDiagram participant U as 客户端 participant CF as Cloudflare Edge participant O as 源站服务器 Note over CF: 默认策略:不支持 JSON 缓存 (DYNAMIC) U->>CF: GET /char.json 请求 CF->>O: 请求绕过 O-->>CF: 返回 JSON 数据 CF-->>U: 响应 JSON 数据 (Cache-Status: DYNAMIC)

方案一:利用 Cache Rules 引入强制缓存

静态资源(CSS、JS)可以通过文件名哈希轻松进行版本管理(Cache Busting),但 API 端点作为资源的唯一标识符,其 URL 必须保持固定,因此难以应用更改文件名的方式。

Cache Busting 强制用户浏览器下载最新版本文件的方法

作为解决上述问题的第一步,我们利用 Cloudflare 的 Cache Rules 设置。这会对具有特定扩展名(*.json)的请求强制应用 Edge 缓存 TTL,从而减少源站请求频率。

  • s-maxage (Edge TTL):中间服务器的缓存有效期
  • max-age (Browser TTL):用户浏览器的缓存有效期

权衡(Trade-off) - 数据一致性问题

然而,较长的 TTL 设置必然会带来数据新鲜度下降的副作用。即使因游戏平衡性补丁等原因修改了原始数据,只要基于唯一 ID 的 URL 结构保持不变,CDN 和浏览器就无法感知文件已发生变更。这会导致在预设的较长 s-maxage 期间内,过时(Stale)数据持续传输给用户,从而引发对服务运营造成致命影响的信息不一致问题。

方案二:自动化的 Cache Purge 策略

为了从根本上解决上述问题,我们将缓存删除逻辑集成到部署流水线中。

sequenceDiagram autonumber actor User as 客户端 participant CF_Edge as CDN participant O as 存储 participant GA as 源站 actor Dev as 开发者 rect rgba(235, 197, 145, 0.1) CF_Edge-->>User: GET /char.json Dev->>GA: 版本更新 activate GA GA->>O: 部署最新版本 GA->>CF_Edge: 调用 purge_cache API GA->>User: 发送信号 deactivate GA end rect rgba(82, 129, 172, 0.1) User->>CF_Edge: GET /char.json CF_Edge->>O: Revalidate O-->>CF_Edge: 返回最新数据 CF_Edge-->>User: 响应最新数据 end