先别急着调“缓存时间”,你得理解缓存到底在干嘛
很多团队一遇到CDN缓存问题,第一反应就是“把TTL调大点”——然后某天用户投诉数据不对,又紧急全部刷新——这种反复拉扯我见过至少二十次,其实CDN缓存远不止一个过期时间那么简单,它是一套从边缘到源站的分布式状态机,核心逻辑只有三个字:“别白跑”。

CDN缓存机制深度拆解,从命中率到一致性,架构师的血泪经验
所谓“白跑”,就是边缘节点没有用户要的资源,不得不回源,一次回源的成本是:用户延迟增加几百毫秒、源站带宽消耗、数据库连接池紧张,而CDN缓存机制的全部努力,就是尽可能在边缘节点命中,同时保证用户拿到的数据“足够新”。
技术概念拆解:缓存不只是“存一下”
1 缓存键(Cache Key)——命中的灵魂
同一个URL,因为请求头不同(比如Accept-Encoding、Cookie、Authorization),在不同用户眼里可能是完全不同的资源,CDN默认把URL作为缓存键,但这往往是最低效的做法。
正确做法:明确哪些请求头参与缓存键计算,比如一个静态图片,User-Agent不应该参与,否则每个浏览器版本都会单独缓存;而一个带?v=1参数的JS文件,参数应该作为缓存键的一部分,否则更新后用户拿不到新版本。
2 缓存策略:TTL只是起点
CDN缓存不是只有“过期-刷新”两种状态,实际有四个层级:
- 强制缓存:TTL内直接返回,不询问源站,性能最高,适合版本化静态资源(如
app.123.js),TTL可以设一年。 - 协商缓存:TTL过期后,边缘节点带
If-Modified-Since或ETag问源站“资源变了吗?”源站返回304(未修改)则复用缓存,返回200才重新拉取,适合API响应、用户头像等变化不频繁的数据。 - 分层缓存:边缘节点回源时,不直接打源站,而是先问中间层缓存(L2节点),这样源站压力再次降低,常见于大型视频平台。
- 主动预热:在业务低峰期或新版本发布前,强制把资源推到边缘节点,比如电商大促的前一天,把所有商品详情页的HTML缓存到全国节点。
3 缓存一致性——终极难题
CDN本质是“最终一致性”系统,强一致(比如用户刚修改了密码,立即在所有节点生效)在CDN里几乎不可能做到,除非放弃缓存,实际方案有三种:
- 全量刷新:暴力清空所有节点某URL的缓存,缺点是成本高、刷完瞬间回源风暴。
- 精准失效:通过API删除特定缓存键(如
/api/user/123),配合版本号机制,比如URL参数加?ts=1630000000,每次更新改时间戳,本质上把缓存失效转化为URL变更。 - 缓存标签(Cache Tag):一组URL共享一个标签,失效时按标签批量删除,所有首页相关资源”打上
homepage标签,更新首页时一键失效这几十个URL。
方案对比:商业CDN vs 自建CDN vs 智能DNS+多源
| 维度 | 商业CDN(如CloudFront、Akamai) | 自建CDN(Nginx/ATS + 多节点) | 智能DNS + 多源站 |
|---|---|---|---|
| 缓存能力 | 内置L1/L2/L3层级,自动优化 | 需手动配置层叠缓存 | 无缓存,靠源站集群扛 |
| 一致性控制 | 提供精准失效、缓存标签API | 需自研失效分发系统 | 无 |
| 运维成本 | 低,SLA保证 | 高,需维护全国节点机器和网络 | 中等,需维护DNS策略和源站组 |
| 适用场景 | 大多数业务,特别是全球化 | 特殊合规要求(金融/政务)或超大规模流量(如视频巨头) | 实时性要求极高(如金融行情) |
血泪对比:自建CDN最坑的一点是“冷启动”,新节点上线后,头几天缓存几乎全空,回源率飙升,源站压力直接翻倍,商业CDN有流量调度池,新节点从邻近节点回源,冷启动平滑很多。
适用场景分析:别拿静态资源的方案套动态API
1 静态资源(JS/CSS/图片/字体)
- 策略:长TTL(半年到一年)+ 版本号URL(如
/static/app.1.0.3.js) - 缓存键:忽略所有请求头,只保留URL
- 坑点:如果用了
CDN-Cache-Control与源站Cache-Control不同的策略,容易造成边缘节点和浏览器双重缓存混乱,建议统一用源站控制,CDN只做“接力”。
2 动态页面(商品详情、新闻文章)
- 策略:短TTL(几秒到几分钟)+ 协商缓存(ETag/Last-Modified)
- 缓存键:按
Host + URI + 用户地域(有时需要),注意不要把Cookie全量加入,否则每个用户独立缓存,命中率接近0。 - 实战技巧:对“登录用户”和“未登录用户”分两套缓存,未登录用户页面内容相同,缓存效率极高;登录用户个人化内容(如“我的订单”)不适合CDN缓存,直接回源。
3 API数据(RESTful/GraphQL)
- 策略:极短TTL(秒级)或不用缓存,但可做“降级缓存”——源站挂了时CDN返回过期缓存(stale-while-revalidate)
- 缓存键:按
HTTP方法 + Path + Query + Authorization(有限制),GET请求可缓存,POST请求一般不缓存(除非幂等)。 - 高级玩法:对读多写少的API(如用户主页信息),用CDN配合后端推送失效消息(Webhook+缓存标签),实现准实时一致。
4 视频/大文件(MP4/Flv/Zip)
- 策略:分片缓存 + 预加载
- 缓存机制:用Range请求实现部分缓存,CDN自动把大文件切成4-8MB的chunk独立缓存,用户拖动进度条时,只缓存被请求的片段。
- 选型注意:商业CDN对分片缓存支持更好,自建需自己实现
range_hash计算。
选型建议:三个问题定方向
1️⃣ 你的用户分布广吗?
如果用户覆盖全国甚至全球,选商业CDN(按节点数付费,自建成本承受不了),如果只在单城市(比如本地生活APP),自建两个节点+商业CDN做备份也够。
2️⃣ 一致性要求多高?
银行交易、库存扣减:别用CDN,或者只缓存HTML外壳(如页面布局),核心数据走实时API。 型网站(新闻、博客、视频):接受秒级甚至分钟级延迟,用CDN长缓存+主动刷新。
3️⃣ 团队运维能力如何?
团队只有2-3个后端,老老实用商业CDN,绝对不要碰自建,团队有专职SRE、运维10+节点且熟悉BGP路由,可以尝试自建CDN核心层(L1/L2),L3仍买商业CDN分担。
最后一句大实话:不要为了“技术自主可控”而自建CDN,除非你的流量大到养得起一个基础设施团队,对绝大多数公司,CDN缓存机制调优的正确姿势是:把源站响应头写对,把缓存键定义清楚,然后充分信任商业CDN的节点调度和淘汰算法——你省下的时间,足以让你好好优化业务代码。
发表评论