设为首页 | 收藏本站欢迎来到卓越网络免费免备案CDN加速,DDoS和CC攻击防御,高防CDN管理平台!

已阅读

那些年,香港图片cdn加速踩过的坑

作者:cdnfine      来源:cdnfine      发布时间:2019-12-28

俗话说,人在江湖飘,哪能不挨刀,再心怀敬畏,亦难免踩坑,有时还是人在家中坐,锅从天上来,下面我们就看看这些锅怎么来的。

一、S3 Website的难言之隐

游戏早在 5 年前 (14 年中)开始触云,AWS 在当时还是神,理念超前,技术牛掰,其为人称道的一点,是他的很多服务可以实现无缝集成;这里要说的就是 S3 与 Cloudfront,S3 作为对象存储服务,提供了 Website 功能,而 Cloudfront 则是图片CDN加速服务,所以很自然地这二个服务可以对接起来,即 S3 作为 Cloudfront 的源站,实际上,这也符合 AWS 的 Best Practice Guidelines。

然而,S3 终究主打的是高可用的对象存储服务,而作为 Website 有着不可克服的限制:

1.不支持 Server Side Include

这年头,网站基本上离不开 SSI 技术了;

2.只支持UTF-8编码

如果文件名是多字节编码,必须采用 UTF-8,否则无法上传到 S3;

3.不支持Multi-Range

调研了下,几乎所有 S3 类的产品,都不支持 Multi-Range,这些产品遇到 Multi-Range 时,要么直接忽略 Range 报头,要么只取第一个 Offset;因此,采用多线程多分段并发下载时就会产生问题。


理想很美好,现实很骨感,我们的海外网站业务,曾经使用 AWS S3 作为源站,网站同学也一度接受了不支持 SSI 的妥协。但这个局面并没有维持太久,去年我们就将海外网站从 S3 迁走,重新使用回了传统的 Web 服务器,原因是我们明显感到网站同学对于 S3 的不乐见,加上业务上云经验的积累让我们不会再轻易跟着 AWS 跑偏。目前还剩下有资源及下载类业务,仍将继续使用 S3 Website 作为源,这方面的风险只能靠规范来回避。

二、QueryString引起的后院之火

QueryStirng 下文简称 QS 或者参数;以下讨论的是静态网站。

1. 对于网站同学,使用QS的目的是实现基于参数展示页面。

一般而言,网站使用参数的场景,会有下面二个:

  • 基于参数作版本控制(CDN 缓存层面)

  • 基于参数进行页面定制(页面逻辑层面)

2. 对于CDN, QS通常会基于二种方式进行缓存

  • 完全忽略参数(通常是作为默认缓存策略,也是最简单有效的策略)

  • 完全忽略或忽略部分的参数

当 CDN 的缓存策略与 QS 的使用场景不匹配时,将会造成缓存穿透,对源站产生较大的压力,极端情况下,缓存近乎失效,回源请求压垮源站。

3. CDN缓存策略与QS的使用场景的适配

这里需要具体分析一下,

  • 如果网站传递的参数是没有意义的随机字符串,这种情况下,CDN 应完全忽略 QS 进行缓存;

  • 如果网站是传递相对固定的字符串(如版本号)作为参数,那 CDN 在缓存时应该带上 QS,使网站可以自主调整发版节奏;

  • 但有时网站同学会说,我传递的确实像是随机数,但是是有意义的参数,比如用户 ID,区服 ID 等信息,业面展示时需要用到这些信息,那总不能也完全抹掉吧?

答案是依然可以抹掉,因为:

  • 抹掉参数,只是在 CDN 缓存层面抹掉,如果产生回源仍然会正常传递参数;

  • 对于静态网站,参数的最终处理是发生在用户端(Javascript),服务器或中间服务器本身不处理参数。

注:有的 CDN 厂商在忽略 QS 时,会默认不传参回源,这是个坑,后面会提到。

4. 表面上看,如果不需要基于QS作版本控制,就可以忽略参数进行缓存,但不同的CDN厂商,对于这个忽略参数的实现,又有差异

我们曾踩过这样的坑:

  1. 用户请求 http://a.com?from=a  ,这个参数是有实际意义的

  2. CDN 忽略参数缓存,在回源时,将参数给抹掉了(即源站将看不到参数)

  3. 源站产生跳转 a.com -> b.com,如果有参数,跳转后保留原参数(但因香港CDN加速未传参数,跳转后地址也就没参数)

  4. 于是,用户请求 http://a.com?from=a ,预期是跳转到 http://b.com?from=a,但是却跳转到了 http://b.com,参数被抹掉了

  5. 由于 CDN 忽略参数缓存,用户后续请求带上任意参数,全部被跳转到 http://b.com,而参数全部被抹掉

这个本身不是缓存去参的锅,是具体实现方式上考虑不周。


针对 QS 的缓存策略,我们曾经主推不去参缓存,让业务有更自主的发挥空间,然而因理解上的偏差,规范执行不是很到位,造成这种(不去参)缓存策略容易产生锅,实际也是产生过了几次锅,为保险起见(业务稳定),针对新的网站我们全部回归到去参缓存,只在当业务方主动要求加参时,我们才针对特定站点做特殊调整。

三、Protocol兼容的混乱之治

1.HTTP本身是很复杂的协议,不同WEB服务器对协议的实现会有差异

目前主流的的 Nginx 与 Apache,我们针对静态文件测试了几个请求方式下返回的状态码,结果如下所示

那些年,香港图片cdn加速踩过的坑

为什么会产生这些差异?我觉得主要有以下 2 个原因:

  • RFC 对协议实现的兼容性要求跨度大,不同厂商实现的兼容程度也就不尽相同

  • HTTP 相关的 RFC 本身就比较晦涩,使得在具体的实现上存在争议;

举例而说,

对于 HEAD 请求方法,RFC 规定其不返回 Body,报头内容与 GET 方法相同;正常情况下,这并没有问题;但如果 HEAD 方法与 Range 报头一起使用呢?

一般情况下,我们会认为,HEAD + Range 时,会返回 206 状态码,但 AWS 说不!他认为 RFC 中 HEAD 方法只是请求文档的 META 信息,并不应该实际去发起 Range 请求,没有发起 Range,自然就不会有 206 状态码,所以 AWS 会返回 200。这听起来没有破绽,故我们也没法反驳。

2.对协议的实现差异,造成我们在对技术栈进行调整,或是在不同的CDN厂商进行切换时,较容易踩坑。

下面这个就是因协议兼容性导致的故障。

游戏主页的流媒体业务,在今年中,其源站从 Apache 切换到了 Nginx,在灰度上线阶段,发现源站不断产生少量的 412 状态码日志,

这个 412 状态码,与条件请求有关,更具体是与 If-Match 请求方法有关(不要与 If-None-Match 相混淆),这二个请求方法简单说明如下:

那些年,香港图片cdn加速踩过的坑

即 412 状态码是因为 If-Match 的报头内容不合法造成,进一步分析,这个故障的原因是:

  • 异常的客户端(播放器),会发送非法的 If-Match 报头

  • 流媒体源站原本使用 Apache,会直接忽略异常的 If-Match 报头

  • 迁移后的 Nginx 则是按照 RFC 处理,当 Not-Match 时,返回了 412

因此,最后的修复方案是简单地忽略掉 If-Match 报头即可。


Protocol is an agreement,我们无法预测谁会违约,目前仰赖一份已有的并持续更新的 checklist,来不断完善验收标准,保障业务的运行稳定。

小结

一路走来,CDN 踩的坑远不只上面提的那些,诸如 3XX 跳转,Range 异常,刷新与挟持问题等,这些远古的坑就不再一一细说。

CDN 填坑无数,但无论什么坑,都没有一种来得凶狠,且一直填不平,这个坑就是:突然收到反馈,某产品某地区某运营商的用户下载有问题,一旦掉这个坑里,很难爬出来,掉坑的原因太多太复杂,这里不细说,针对这个坑,我们目前采取了 detect + fallback 机制来尝试脱坑,取得了一些改善,但还做不到全场景覆盖,此时,就需 CDN 的 MM 们出马了。

Keywords: 免费CDN加速 免备案CDN加速 高防CDN加速