背景
CDN是一种分布式加速系统。不管如何,只是作为加速,返回给客户的内容需要和源站保持一致,所有地区节点的用户访问统一资源得到的返回内容应该是一致。但我们在实际的使用过程中,可能会遇到有的用户发生了不同节点访问,返回的内容是不一致的情况。 这是怎么回事呢, 我们来看下下面这个例子。
问题描述
某用户反馈CDN源站COS的mp4文件使用cdn加速域名同一资源连接访问(https://xxx.xxxxx.com/xbb/app/2020/12/24/20201224/xxx_Android.mp4),有的节点返回是视频(符合预期),有的节点返回是图片(不符合预期)
诊断与分析
- 问题复现:
由于我们测试所访问的节点和用户访问到的节点不一定相同。测试自己所在节点返回符合预期的mp4类型不代表其他节点就一定都是mp4. 结合用户反馈的异常节点,绑定host进行访问, 如下可见, 确实返回了图片类型的资源。
curl -lvo /dev/null https://xxx.xxxxx.com/xbb/app/2020/12/24/20201224/xxx_Android.mp4 --resolve "xxx.xxxxx.com:443:122.228.82.186"
2. 源站分析及配置检查
检查返回的图片和源视频的关系,发现返回的图片是视频的首帧的图像。 同时去检查客户使用的源站是COS源站。发现客户开启了COS万象的裁图水印功能,访问源站带参数访问源站时为万象截图, 不带参数范围视频时是mp4视频。
如:
http://xxx.cos.ap-beijing.myzijiebao.com/xbb/app/2020/12/24/20201224/xxx_Android.mp4 (cos返回mp4)
http://xxx.cos.ap-beijing.myzijiebao.com/xbb/app/2020/12/24/20201224/xxx_Android.mp4?ci-process=snapshot&time=1&format=jpg(cos返回mp4的首帧图片)
3. CDN缓存策略检查
检查CDN域名设置,发现这个域名开启了过滤参数缓存。
开启了过滤参数缓存也就是根路径缓存, 带参数和不带参数的缓存的都是一样的,访问的时候也是带参数和不带参数访问的都是一样的。 那这里为什么会出现多节点缓存不一致的情况呢?
4.根因分析
下面我们模拟一下整个缓存建立的过程,如下这个图:
红色虚线框是缓存建立的过程。 由于第一次访问到节点A和节点B的时候都没有缓存, 这时候请求都直接回源获取缓存。 源站根据回源请求的url各种返回了图片和视频。这个时候节点A和节点B收到源站吐出的不通类型的数据, 并建立起缓存。 当这两个节点再次收到终端用户的访问时, 发现已经有缓存了, 就把缓存吐给终端用户。 这样我们就看到,不同的节点返回的数据不一致了。 终端用户访问带一个已经建立缓存的节点, 无论是带参数还是不带参数, 都会直接命中缓存(因为这个域名开启了过滤参数缓存)。
所以根因是由于源站是根据参数吐数据, 而CDN是忽略参数进行缓存,才导致了同一个请求访问到不同节点,收到的返回数据不一样。
那么如果我们CDN节点不开启过滤缓存的话,会是什么情况呢。 这里我们也模拟一下如图所示:
大家可以看到, 如果不开启过滤缓存, 也就是全路径缓存。 那么cdn节点第一次收到带参数和不带参数的请求都会去回源, 节点上也会缓存2份源站的资源。 当用户请求过来以后, 会根据带参数或不带参数去命中对应的资源。 如此就不会出现不符合预期的情况了
解决方案
对于源站设置了根据参数吐出不同的资源的情况下, 建议客户 关闭"过滤缓存"功能,防止不同的节点缓存的数据不一致。
小结
用户通过 URL 进行资源访问时,可能会携带一些具有特殊作用的参数,如携带的参数表示不同的资源,这种场景下需要关闭过滤参数,由完整的 URL 作为缓存键,分别进行内容的缓存,来进行资源区分。
需要注意COS源站万象的裁图水印等功能具备此功能, 很多用户容易忽略。 如果启用了cos的这个功能, 建议cdn侧一定关闭过滤缓存这个功能, 避免由于源站按参数吐资源导致的访问cdn缓存不符合预期的情况。 其他三方源站同理。
该类问题的核心在于cdn的缓存需要和回源时源站返回数据一致性的机制保持一致。如果源站不存在参数导致的资源发送变化,如只是签名校验的时间等, 那么就可以放心开启过滤参数缓存,提高命中率。