
说到CDN缓存命中率这个问题,可能很多做直播业务的朋友都有过类似的经历:明明CDN节点铺得挺广,但命中率就是上不去,服务器压力始终下不来,成本也跟着蹭蹭往上涨。我自己在工作中也没少跟这个问题打交道,今天就想把这个话题聊得透彻一些,把那些坑和解决方案都掰开揉碎了讲讲。
先说个场景吧。去年有个项目,直播平台的静态资源命中率只有60%左右,按理说不算太低,但业务量一大,源站带宽费用就吃不消。后来我们花了大概两个月时间系统性地优化了一波,把命中率提升到了85%以上,效果还挺明显的。这个过程中积累了一些经验,也踩了不少坑,今天就想着把这些分享出来,或许对正在做类似事情的朋友有点参考价值。
在说优化方法之前,咱们先搞清楚为什么命中率这个问题值得花这么大精力去研究。你可能听说过”缓存为王”这种说法,在CDN这个领域确实有一定道理。命中率直接影响的是用户体验和成本控制两个方面,这俩还往往是矛盾的——你想要更好的体验就得堆资源,成本就下不来;而想要控制成本,缓存又可能不够高效,用户加载就变慢。
直播场景下这个问题尤其突出。传统点播内容的缓存策略相对简单,因为文件是固定不变的,只要设置好缓存时间基本上就能搞定。但直播不一样,直播流是实时产生的,虽然我们这里讨论的是静态加速,但直播页面里的HTML、CSS、JavaScript这些静态资源,以及缩略图、弹幕素材之类的,它们的更新频率、更新逻辑都跟点播内容有很大区别。如果不做针对性的优化,缓存策略很容易出问题。
举个具体的例子你就明白了。假设一个直播平台的首页,理论上应该有很多内容可以缓存,但实际情况可能是:直播间的封面图每隔几分钟就换一次,排行榜每小时更新一次,礼物特效可能每天都在迭代。如果这些资源都用统一的缓存策略,要么缓存时间太短导致频繁回源,要么缓存时间太长导致用户看到过期内容,怎么都不合适。这就是命中率上不去的根本原因——缓存策略和业务特性没对齐。
想要优化缓存命中率,首先得搞清楚哪些因素在影响它。我把这些问题分成几类来说,这样思路会清晰一些。

缓存键(Cache Key)是CDN判断”这个请求和那个请求是不是同一个”的核心依据。很多时候命中率低,不是说CDN节点没有缓存,而是不同的请求在CDN眼里被当成了不同的资源,导致缓存被割裂了。
最常见的问题就是URL后面带了各种参数。比如用户访问同一个直播间的首页,可能带的是`?from=app`或者`?t=123456`这样的参数,这些参数在CDN看来是不同的URL,自然就会去源站拉取。实际上这些请求返回的内容可能完全一样,白白浪费了缓存空间。
还有一个容易被忽略的问题是URL的大小写敏感。有些服务器操作系统对大小写不敏感,但CDN的缓存系统往往是敏感的。`/Live/Index.html`和`/live/index.html`会被当成两个不同的文件,如果网站上这两种链接都在用,缓存命中率自然就上不去。
缓存时间的设置是个技术活,也是艺术活。时间设置得太长,用户可能看到过期内容;设置得太短,缓存又形同虚设。这中间的平衡点需要根据业务特性去找。
我见过两种极端情况。一种是保守型策略,所有静态资源都设置几分钟的缓存时间,结果直播封面图、排行榜这些更新频率不高的资源也频繁失效,源站压力始终下不来。另一种是激进型策略,设置很长的缓存时间,结果用户看到的是几天前的直播界面,礼物图标都换了一茬了页面上还是旧的,体验特别差。
正确的做法应该是分层设置缓存时间。不同类型的资源需要不同的对待方式,这个我们后面会详细说。
还有一个比较隐蔽的问题是缓存过期时间的计算方式。很多CDN服务用的是文件最后修改时间(Last-Modified)来决策缓存策略,如果源站服务器的时间设置不正确,或者文件内容变了但最后修改时间没变,都可能导致缓存失效策略失效。这个问题排查起来比较麻烦,但确实会影响命中率。

HTTP响应头里的Cache-Control、Expires、ETag这些字段都会影响CDN的缓存行为。如果源站配置不当,CDN可能不会缓存内容,或者缓存时间很短。
最典型的就是Cache-Control里面设置了`no-cache`或者`no-store`。前者意味着CDN每次都要和源站验证才能使用缓存,后者更彻底,直接不让缓存。如果源站意外设置了这些头,缓存命中率肯定高不了。
另一个问题是Vary头设置不当。Vary头告诉CDN需要根据哪些请求头来决定是否使用缓存。如果设置了这个头,CDN就会把不同的请求头组合当成不同的缓存版本。比如有的网站启用了`Vary: Accept-Encoding`,这本身是合理的,但如果同时也设置了`Vary: User-Agent`,而网站又有很多种客户端在访问,缓存就会被切得很碎,命中率自然就下来了。
前面说了问题所在,下面聊聊具体的优化方法。这些方法有的是我们实践中用过的,有的是从同行那里学来的,都经过验证,效果还不错。
首先要做的就是在CDN控制台或者配置里设置缓存键的参数过滤规则。绝大部分CDN都支持忽略URL中特定参数的功能,你要做的是梳理出哪些参数是业务必需的,哪些是客户端自己加的、可忽略的。
比如直播场景下,通常可以忽略的参數包括:来源标识(from参数)、时间戳(t或timestamp参数)、设备标识(如果不影响内容展示的话)、分辨率参数(如果服务端会自动适配的话)。而那些确实会影响内容返回的参数就要保留,比如不同清晰度对应的参数可能就需要保留。
清理工作还包括统一URL格式。大小写问题最好在源站层面解决,通过URL重定向把所有访问都统一到一个小写或者大写形式上,避免同一个资源有多个URL版本。这个工作看起来简单,但实际做起来可能要涉及整个网站的URL规范梳理,工作量不小,但做了之后对命中率的提升是很明显的。
前面提到不同类型的资源应该有不同的缓存策略,这里详细说说怎么分这个层。根据我们的经验,直播静态资源大概可以分成这么几类:
| 资源类型 | 典型内容 | 建议缓存时间 | 说明 |
| 核心框架资源 | JS框架、CSS框架文件 | 7-30天 | 更新频率极低,可以设较长时间 |
| 业务逻辑资源 | 业务JS代码、页面模板 | 1-7天 | 更新较频繁,但不需要实时 |
| 视觉资源 | 图标、图片、字体 | 7-30天 | 视觉更新频率较低 |
| 直播相关 | 直播间封面、排行榜、礼物图片 | 5分钟-1小时 | 需要一定实时性 |
| 用户生成内容 | 用户头像、弹幕素材 | 1-24小时 | 有一定实时性要求 |
| 页面类资源 | HTML页面 | 1-10分钟 | 更新相对频繁 |
这个分层不是绝对的,要根据实际业务情况调整。核心原则是:更新频率越高的资源,缓存时间越短;更新频率越低的资源,缓存时间可以设得越长。
在声网的实践中,我们还会对关键资源设置更细粒度的缓存策略。比如直播间的封面图,虽然理论上是每小时甚至更久更新一次,但有时候会提前上线新活动,需要临时更换。这种情况我们会通过URL参数的方式强制刷新特定资源,而不是修改全局缓存策略,这样既保证了日常的缓存效率,又保留了灵活应对的能力。
源站的HTTP响应头配置对缓存命中率影响很大,需要专门检查和优化。首先要确保Cache-Control头设置正确,静态资源应该设置为较长的缓存时间,加上必要的验证指令比如`must-revalidate`。`no-store`要谨慎使用,除非资源确实不能缓存,比如包含用户敏感信息的响应。
ETag和Last-Modified这两个验证头要不要开启,需要权衡一下。开启的好处是缓存过期后可以通过验证判断内容是否真的变了,如果没变就继续使用缓存,可以减少回源流量;坏处是每次验证都需要一次回源请求,会增加源站的QPS压力。对于访问量很大的静态资源,可以考虑关闭验证头,直接设置较长的缓存时间,靠TTL来控制缓存失效。
Vary头的设置要格外谨慎。只添加那些确实会影响内容返回的请求头。比如如果网站需要根据用户的语言偏好返回不同语言版本的资源,那`Accept-Language`就要加到Vary里。但如果只是因为压缩格式不同(比如gzip和br压缩),其实可以只保留`Accept-Encoding`,因为CDN通常会自动处理压缩格式的适配,不需要在Vary里显式声明。
除了被动地让缓存自然形成,有时候主动预热效果更好。直播场景下,有很多资源是可以预判用户会访问的,比如热门直播间的内容、即将开始的活动的宣传素材、排行榜上的头部内容。
预热的方法大概有两种。一种是提前把资源推送到CDN节点,这个可以通过CDN提供的API或者控制台批量操作;另一种是利用用户访问自然预热,比如在直播间列表页面提前加载热门直播间的封面图,这样当用户真正进入直播间时,这些资源已经在缓存里了。
我们实践下来,预热对于那些访问量集中、时效性要求高的资源效果特别好。比如一场重要直播活动开始前,我们会提前把活动页面相关的静态资源都预热一遍,这样活动刚开始的瞬间就不会出现缓存miss导致源站压力骤增的情况。
缓存优化不是一次性的工作,需要持续监控和调整。这里说的监控不只是看命中率数字,更重要的是分析命中率的构成——哪些资源命中率高,哪些资源命中率低,原因是什么。
通常CDN控制台都会提供一些监控报表,建议重点关注这么几个维度:按资源类型的命中率分布,找出命中率特别低的资源类型;按域名或者路径的命中率分布,找出需要重点优化的业务模块;按时间段的命中率变化,找出可能在特定时段失效的规律。
我们自己在声网做的一个实践是建立命中率告警机制。当某个时间段或者某个业务的命中率低于阈值时,自动发送告警提醒相关人员排查。这样可以在问题影响扩大之前及时发现和处理。
在优化缓存命中率的过程中,有些坑我踩过或者见过别人踩过,这里列出来提醒一下。
命中率不是越高越好,追求100%的命中率有时候会适得其反。比如为了提高命中率,把所有资源的缓存时间都设得很长,结果用户看到过期内容,体验反而下降了。合理的目标是在缓存效率和内容时效性之间找到平衡点,而不是一味追求数字好看。
有时候命中率上不去,不是因为CDN配置有问题,而是源站本身响应太慢或者不稳定。如果源站响应时间波动很大,CDN可能会更保守地使用缓存;如果源站经常返回错误,CDN的缓存也会受到影响。所以优化CDN配置的同时,也别忘了保证源站的健康状况。
大公司可能有多个业务线共用CDN,不同业务线的配置可能相互影响。比如A业务设置了某个缓存规则,意外覆盖了B业务的规则,导致B业务命中率下降。建议定期审计CDN配置,确保各个业务线的配置不会互相干扰,并且有完善的变更管理流程。
CDN缓存命中率的优化,说到底是一个理解和匹配业务特性的过程。没有放之四海而皆准的最优解,只有最适合当前业务情况的方案。
在这个过程中,我发现最重要的能力是”既能深入技术细节,又能跳出技术思考业务”。既要懂CDN的工作原理、缓存协议这些技术知识,又要理解直播业务的实际需求、用户的使用场景。只有把这两方面结合起来,才能做出真正有效的优化。
另外,优化工作要循序渐进,不要试图一步到位。先从影响最大的问题入手,验证效果之后再下一步。保持监控和数据驱动的决策,这样即使某个方案效果不好,也能快速发现并调整方向。
希望这些经验对正在做类似工作的你有那么一点帮助。如果有什么问题或者有不同的见解,欢迎交流讨论。
