原创: 小包子大 网易游戏运维平台 前天
小包子大
06年加入网易游戏,先后负责过多个端游/手游产品的运维工作;多年运维生涯,历经数次运维技术变革;本人关注广泛,Web/CDN,自动化,分布式等,欢迎来侃;作为十多年运维老兵, 平日写些别人看着晦涩的东西,擅长手术刀式的运维杂症分析。
前言
俗话说,人在江湖飘,哪能不挨刀,再心怀敬畏,亦难免踩坑,有时还是人在家中坐,锅从天上来,下面我们就看看这些锅怎么来的。
一、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的目的是实现基于参数展示页面。
一般而言,网站使用参数的场景,会有下面二个:
2. 对于CDN, QS通常会基于二种方式进行缓存
当 CDN 的缓存策略与 QS 的使用场景不匹配时,将会造成缓存穿透,对源站产生较大的压力,极端情况下,缓存近乎失效,回源请求压垮源站。
3. CDN缓存策略与QS的使用场景的适配
这里需要具体分析一下,
答案是依然可以抹掉,因为:
注:有的 CDN 厂商在忽略 QS 时,会默认不传参回源,这是个坑,后面会提到。
4. 表面上看,如果不需要基于QS作版本控制,就可以忽略参数进行缓存,但不同的CDN厂商,对于这个忽略参数的实现,又有差异我们曾踩过这样的坑:
这个本身不是缓存去参的锅,是具体实现方式上考虑不周。
针对 QS 的缓存策略,我们曾经主推不去参缓存,让业务有更自主的发挥空间,然而因理解上的偏差,规范执行不是很到位,造成这种(不去参)缓存策略容易产生锅,实际也是产生过了几次锅,为保险起见(业务稳定),针对新的网站我们全部回归到去参缓存,只在当业务方主动要求加参时,我们才针对特定站点做特殊调整。
三、Protocol兼容的混乱之治
1.HTTP本身是很复杂的协议,不同WEB服务器对协议的实现会有差异
目前主流的的 Nginx 与 Apache,我们针对静态文件测试了几个请求方式下返回的状态码,结果如下所示
为什么会产生这些差异?我觉得主要有以下 2 个原因:
举例而说,
对于 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 相混淆),这二个请求方法简单说明如下:
即 412 状态码是因为 If-Match 的报头内容不合法造成,进一步分析,这个故障的原因是:
因此,最后的修复方案是简单地忽略掉 If-Match 报头即可。
Protocol is an agreement,我们无法预测谁会违约,目前仰赖一份已有的并持续更新的 checklist,来不断完善验收标准,保障业务的运行稳定。
小结
一路走来,CDN 踩的坑远不只上面提的那些,诸如 3XX 跳转,Range 异常,刷新与挟持问题等,这些远古的坑就不再一一细说。
CDN 填坑无数,但无论什么坑,都没有一种来得凶狠,且一直填不平,这个坑就是:突然收到反馈,某产品某地区某运营商的用户下载有问题,一旦掉这个坑里,很难爬出来,掉坑的原因太多太复杂,这里不细说,针对这个坑,我们目前采取了 detect + fallback 机制来尝试脱坑,取得了一些改善,但还做不到全场景覆盖,此时,就需 CDN 的 MM 们出马了。
往期精彩
智能监控中的时间序列预测
使用 d3.js 绘制资源拓扑图
运维里的人工智能
CI构建环境下的docker build最佳实践
Web站点接口优化实践