接入CDN或反向代理后缓存命中率偏低,绝大多数原因并非节点或厂商问题,而是源站响应头设置、缓存键默认策略以及动态请求占比过高这三类配置陷阱导致的。
先搞清楚:命不中到底该看哪张报表
很多朋友一看到命中率数字不好看,第一反应就是找节点服务商理论,但先别急,市面上主流的CDN控制台,通常把命中率拆成了两类指标:请求命中率 和 流量命中率,请求命中率算的是“有多少个请求直接打在了边缘节点上没回源”,流量命中率算的是“回源的字节数占总字节的比例”,对于图片、视频这类大文件站点,流量命中率才是王道;对于API接口或者HTML页面,请求命中率更敏感。
如果接入后发现请求数上去了但流量命中率惨淡,先检查是不是命中日志里出现了大量 304 Not Modified 状态码,这玩意儿不算缓存Miss,但如果你用的是裸日志分析,它会被误判成未命中。行业共识认为,304响应占请求总数的比例超过5%时,报表失真问题已经足以干扰判断了。
源站响应头里的“自杀式”指令
这是最普遍、也最容易踩的坑,源站输出的HTTP响应头里,有几个字段会直接命令CDN节点不要缓存,或者缓存了也不敢用。
Cache-Control: private:这等于告诉节点“这数据只给单个用户看,你别存”,登录后的个人中心、购物车接口返回这个头没错,但很多站点把首页、列表页也统一加上了这个头。Cache-Control: no-cache:注意,这个头不是“不缓存”,而是“缓存前必须先回源验证”,如果你没在CDN控制台覆盖这个头,那么每次请求都会穿透到源站做一次校验,命中率自然归零。Set-Cookie干扰:只要响应里带着Set-Cookie,简米云、酷番云、Cloudflare等平台默认就不会缓存该响应,很多老旧的PHP程序即使页面没做登录功能,也会在每次请求时种下一个会话Cookie,直接导致整站命中率失控。Vary: User-Agent:这个头要求节点按UA区分缓存版本,如果源站对所有访客都输出这个头,等于告诉CDN“每个浏览器都得存一份副本”,命中率会被极端稀释。
实操检查路径:用浏览器F12打开网络面板,或者用curl -I https://你的域名/一个静态资源,直接看响应头里有没有上述字段,发现哪个接口或路径异常,就需要在CDN控制台的“回源HTTP头修改”或“缓存配置”里强制删除或覆盖这些头。
还有一种情况更隐蔽:同一条URL在不同时间返回了不同的Cache-Control,比如促销活动页,白天是public, max-age=3600,晚上切流量时变成了private,节点按照最后一次回源的响应头来更新缓存策略,结果就是缓存刚建好就被判了死刑。
缓存键(Cache Key)粒度太粗或太碎
缓存键是CDN判断“两个请求是不是同一个资源”的依据,很多接入时默认配置的缓存键只包含Host和URL路径,这导致了两种极端:
粒度太粗:参数污染导致误命中
URL里的?from=wechat、?tracking_id=123456这类营销参数,在默认配置下会被当成不同的缓存键,用户每点一次带不同参数的链接,节点就得重新回源拉一次。据统计,电商类站点在未做参数过滤时,因为Query String差异导致的额外回源,占到了总回源量的三成以上。
粒度太碎:设备/语言维度被打散
如果缓存键加入了Accept-Language或者Device-Type,那么每个语种、每种设备都得单独存一份副本,中小站点如果目录页本来一天就几百个请求,被拆成四五个版本后,每个版本的请求频率根本不够看,还没等到缓存过期就已经被剔除了。
建议的配置策略:
- 在CDN控制台开启“过滤参数”或“忽略Query String”,只保留白名单参数(如
?id=、?sku=)。 - 缓存键尽量不要包含UA、Language这类高基数变量,要区分移动端和PC端,优先用不同的子域名,而不是在缓存键里做文章。
- 给静态资源(js/css/img)单独分配一个不带问号的路径,或者用固定的版本号
v=20260101,而不是随机的v=abc123def。
回源协议与Host头不一致
接入CDN时,源站类型填的是IP,但回源Host头填的是源站域名,如果这个配置错了,或者源站上绑定了多个站点,节点回源时可能拿到的是默认站点的内容,而不是你域名对应的内容。
更麻烦的是,当源站开启了HTTPS强制跳转,而CDN回源方式还是HTTP协议时,节点每次回源都会收到一个301跳转,此时节点会去拉取跳转后的资源,但跳转后的域名往往不在缓存服务范围内,于是陷入“回源->301->再回源”的循环,没有产生实际命中,反而增大了源站压力。
业内专家指出,排查这类问题最快的方法是看CDN日志里的cache_status字段:如果大量记录显示MISS,而且回源耗时超过1秒,多半就是源站跟节点之间的协议握手或跳转出了问题。
这里顺带提醒一个很多人忽略的点:如果源站使用了Nginx的gzip模块,且压缩级别设置得很高(比如9级),而CDN节点也开启了自动压缩,两边压缩出的结果不一致会导致ETag校验失败,节点每次都要重新压缩并回源对比,命中率同样会掉。
与静态资源混在同一个域名
很多站点为了省事,把接口(/api/getUserInfo)和静态图片(/upload/avatar.jpg)都放在同一个域名下,CDN分不清哪个是动态哪个是静态,只能套用最保守的策略全部回源,这就回答了一个常见的疑问:cdn缓存命中率低的原因是不是就是动态内容太多了? 多数情况下,答案是肯定的。
解决办法不是把动态请求也强行缓存,而是拆分域名:
static.你的域名.com:专门放图片、CSS、JS,缓存时间设为7天或30天。api.你的域名.com:不开启缓存,或只开启缓存但不缓存响应体。www.你的域名.com:HTML页面,开启动态加速,设置短缓存(如60秒)配合stale-while-revalidate。
如果出于成本考量不想加域名,那就在CDN控制台里按路径前缀区分,比如/assets/走长缓存,/data/走不缓存策略。没有路径规则的缓存配置等于什么都没配,这句话可以贴在你工位旁边。
缓存过期时间(TTL)设置与业务场景错位
TTL设置不当是新手最容易犯的错,但表现形式五花八门:
- 对新闻首页设了24小时缓存:用户看到的内容永远是昨天的,这倒不会导致命中率低,但引流效果会断崖式下跌。
- 对产品详情页设了60秒缓存:如果这个页面平均每小时只有10次访问,缓存刚建立就过期,几乎100%回源,这种“形同虚设”的缓存,对命中率贡献约等于零。
- 对频繁变化的验证码图片设置了0秒:这没错,但如果你把验证码请求也统计进了整体命中率,分母就被拉大了。
合理的TTL设置参考:
类型 | 建议TTL | 说明 |
| — | — | — |
| 带版本号的静态资源 | 30天以上 | 文件名变了就相当于新资源 |
| 文章/新闻正文页 | 10-30分钟 | 兼顾更新时效与命中率 |
| 首页/列表页 | 60-120秒 | 用短缓存+异步刷新替代长缓存 |
| 个性化接口 | 0秒 | 不要缓存,走正常回源 |
| 地理位置查询API | 5-10分钟 | 数据本身变化不频繁 |
这里说一个概念:缓存命中率多少算正常?对于纯静态资源站点,长缓存文件占比高,命中率做到95%以上不奇怪,对于电商、资讯类混合站点,整体请求命中率在80%左右已经算健康,流量命中率能到90%以上就很不错了,低于70%就要认真复盘上述问题。
节点缓存空间不足导致的提前淘汰
这也是一个被低估的因素,CDN每个节点的存储空间是有限的,如果接入的站点资源总量远大于节点缓存容量,那么即便是设置了很长时间的TTL,新请求也会把旧资源挤出去,导致明明还有效的缓存失效。
这种情况多见于图片素材站或高分辨率视频预览站,文件单个体积大、总量多,而节点分配的资源少。现代CDN通常基于LRU算法淘汰不常用的缓存失血的往往是那些低频但重要的长尾资源。
应对思路:
- 优先给大文件设置单独的资源包或专属加速通道,必要时购买更大容量的缓存服务。
- 将超大的视频文件改成分段切片存储,让节点按片段缓存,而不是整个文件一起缓存。
- 开启“Range回源”支持,至少保证大文件部分命中,挽回一半以上的流量成本。
针对上述问题的验证与止血清单
排查这类问题,不要靠猜,按下面的步骤走一遍:
- 打开CDN控制台的“缓存命中率”报表,切换到按状态码分布视图,确认
200和304的具体占比。 - 使用“刷新预热”工具,手动预热一两个核心页面URL,然后频密地访问这些URL,观察报表里是否出现
HIT记录,如果没有,大概率是规则没生效或被源站响应头覆盖。 - 直接回源服务器抓包,对比源站返回的
Cache-Control与CDN控制台配置的“源站缓存控制”选项哪个优先级更高。 - 用“日志分析”功能拉取最近一小时的请求日志,按
host、uri、cache_status三个字段分组统计,MISS次数最多的Top 20 URL,就是问题的核心病灶。 - 查看“回源流量带宽”与“命中流量带宽”的峰值曲线重合度,如果两条曲线完全重合,说明CDN形同虚设,问题在配置层;如果回源流量在晚间突然飙升,可能的触发点则是源站动了缓存头或刷新了节点。
一些确实不属于CDN职责范畴的场景
最后得说句公道话,有些情况,就算你把上面所有配置都调对了,命中率也上不去:
- 私密用户内容:比如网盘的加密文件、付费课程的播放地址,这类内容天然需要鉴权,任何缓存策略在鉴权面前都要让位。
- 实时性极强的数据:股票行情、赛事比分、库存余量,这些数据超过3秒不更新就是错的,CDN只能提供“不缓存”或“极短缓存”的选项,没法变魔术。
- 访客本人的浏览行为:如果页面上的核心元素是根据Cookie动态拼装的,比如推荐算法千人千面,那无论怎么优化都白搭,因为每个访客看到的页面都不一样。
面对这类诉求,合理的做法是把动态部分用iframe或异步Ajax分离开来,让静态骨架走CDN缓存,让动态区域走直连。 这样既能保住用户体验,也能让命中率报表回归正常。
Q:接入CDN后缓存命中率偏低,但源站压力并没有增加,这是怎么回事?
A:源站压力没增加,但命中率低,通常是因为报表里的“命中”只计算了从内存或本地磁盘直接返回的请求,而客户端自身的304协商缓存(浏览器缓存)被计入了回源请求但实际没消耗源站计算资源,这种情况下不用过度焦虑,调出节点的回源流量带宽看趋势即可,只要回源带宽没有异常冲高,说明服务整体是健康的。
Q:网站全部改用HTTPS后,缓存命中率相比HTTP时下降明显,正常吗?
A:正常,但不完全是协议本身的锅,HTTPS访问下,CDN节点与源站重新建立TLS握手需要额外消耗时间,同时部分CDN服务商对HTTPS回源的缓存策略默认更保守,你可以手动在控制台开启“HTTPS回源”并设置“链路复用”(Keepalive保持长连接),命中率通常会在24小时内回升。
Q:缓存命中率低频波动,时高时低,是什么在捣乱?
A:优先查看源站那边是否有定时任务在批量刷新缓存,比如CMS编辑后台保存文章时顺手提交了全站URL刷新,另一个常见来源是移动端分享链接携带的时间戳参数,这些参数在进入CDN时被直接哈希进了缓存键,导致同一条URL产生了上千个变体,启用“过滤参数”并只保留业务必需参数,低频波动的问题会显著缓解。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/792790.html


