37手游打包系统CDN迁移平滑落地

568 阅读12分钟

前言:

在大多数人眼中,CDN厂商的迁移是一项高风险且高成本的工程。许多公司在选定某家CDN云厂商后,往往会配套使用其对象存储等资源,极少轻易更换。然而,随着云服务市场的不断发展,CDN厂商百花齐放,总会有一些性价比更高的新兴云厂商出现。这时,企业便面临两难选择:

  1. 迁移到新云厂商:风险较高,需制定严谨的迁移方案,同时还要承担一定的云端成本转移费用;

  2. 继续沿用旧有云厂商:成本居高不下,且原有厂商可能存在性能或监控等方面的问题。

image-2025-5-10_16-46-20.png

2024年初,37手游在打包系统业务上,正好遇到了这样的抉择。

起因——无法承受的成本之痛

在阐述成本问题之前,我们先要介绍下背景:

我们手游打包系统的投放的业务形态,是将对象存储和CDN结合使用,从CDN侧直接回源到对象存储,而对象存储实际存放的就是我们游戏的包体。

image-2025-5-18_23-20-57.png

因此,在23年中到24年初,由于我们有投放大量的游戏,导致实际我们的对象存储存储的包体越变越多,对应的CDN访问费用也水涨船高,此时的费用已经到了运维同学会天天叫苦不迭的程度;

其中,成本占大头的为两大部分:

第一部分:对象存储的存储成本费用

这部分主要是出于37手游本身的广告投放多的业务形态,我们在对象存储上存放的游戏包体是非常的多的,基本上一款游戏,在对象存储里就存放上千个包体,且每款游戏的包体容量基本都处于500M到2G的区间。

第二部分:CDN流量的访问费用

这部分主要跟第一部分的费用是相辅相成的,存放的包体的数量多,实际访问回源的数量也就多,加上本身CDN的流量访问费用,实际也就会跟着水涨船高了

(不过,第二部分的费用原因,我们后面才发现,这个费用的原因判断是错误的,这部分我们在文章的后面会提及)

image-2025-5-10_16-59-40.png

思路——成本优化的可行性评估

在成本的大问题面前,我们一开始想到的思路方向无非是两个

第一部分:减少对象存储的费用

从旧有的包体的存储出发,减少旧有包体存储的数量,以及新增包体的数量或者说通过某种方式,压缩包体的内容空间,从而减少对象存储本身的费用成本。

image-2025-5-10_16-29-6.png

第二部分:减少CDN本身的费用

从CDN访问角度出发,减少CDN本身回源次数,优化对应的缓存策略,并进行内容优化(资源去重与缓存利用等)

image-2025-5-10_16-34-7.png

对于这两部分的思路方向,我们其实也是很好评估的得出结论的

针对第一部分,我们可以从业务上出发,尽量清除掉存放的对象存储的包体,

  • 对于旧有的,一段时间内没有被访问过的,且没有产生投放计划的包体,这部分包体在投放的意义上已经不大,因此可以被清除掉。
  • 对于压缩包体空间,以及减少新增包体数量这一方面,由于这块涉及到安卓包体以及业务层面上的改造,实际牵涉到的业务会很多,因此我们先暂不考虑

针对第二部分,我们也很好的得出结论

  • 优化缓存策略,减少CDN的回源:这块由于我们打包业务的特性,由于更新游戏包体的周期会很长,我们通过延长了CDN缓存过期的时间,减少了CDN回源的次数,优化了一部分的流量费用
  • 内容优化:同上,由于涉及业务安卓包体层面的改造,因此也暂不考虑

从结论而言

综合上面两部分下来,我们评估下来,确实也能节省一部分的成本,但实际我们存放的包体,以及CDN流量的费用还是非常高,此时,由于我们和火山云厂商有比较深度的合作,从他们口中得知了,他们的CDN以及对象存储的单价都非常的低,比起我们用于原有的云单价竟然要节省50%

这时候,我们便无法不考虑,对象存储迁移,以及CDN迁移的可行性了。

措施——对象存储迁移以及CDN迁移的循序渐进

对于实际的迁移过程中,我们实际遇到的难点,可根据不同的业务侧,分为以下几点

  • 运维侧:

    • 如何确定迁移后,对象存储。CDN的性能是否有对应的保证?
    • 如何控制对象存储和CDN迁移过程中,产生的成本费用?
    • 如何保证迁移中以及迁移后,对应的CDN下载质量监控?
  • 技术侧:

    • 如何保证制定对应的灰度方案,使到每次受迁移影响的用户尽可能的在某个范围内?

    • 如何保证在迁移过程中,包体数据的一致性?

    • 如何保证在异常情况下,包体数据的回滚?

image.png

针对这些难点,我们也是构想了对应的解决思路,为如下:

对象存储和CDN的性能保证?

对迁移后的CDN的性能保障, 我们通过拨测, 实际测量了各大CDN厂商的性能,最终从网络性能,以及传输性能而言,火山CDN都是属于是第一梯队的,而且优于我们原有的CDN(这里由于隐私原因,不进行数据的展示)

对象存储和CDN在迁移过程中产生的成本费用?

这块成本费用主要是为不同云对象存储之间拷贝费用, 我们一开始想到为两种方案

  • 公网对拷:

iShot_2025-05-23_12.23.26.png

  • 优点:全托管式迁移,不需人工校验介入数据,简单粗暴

  • 缺点:公网传输产生的流量费用成本高

  • url列表迁移:

image-2025-5-21_0-21-25.png

  • 优点:走CDN请求URL限速下载,成本较少。
  • 缺点:速度慢,且实际业务配合灰度方案不好制定

综合评估下来,出于安全性以及业务形态,我们采用的还是第一种方案,但所幸的是这种迁移的成本是一次性的,而且对比于我们实际迁移能节省下来的费用,简直是九牛一毛。

在进行对象存储的拷贝之前,我们还是尽量的把原有对象存储里能删除的包体都删了,来保证说迁移的量尽可能的少

用户影响量级的控制?

由于我们的包体是根据不同业务类型,去绑定对应的CDN域名的,因此我们的迁移灰度可天然以域名为维度,用DNS分配解析流量占比的方式,将用户下载的流量按比例来进行分配,从而达到说控制影响范围的目的。

image-2025-5-22_0-8-2.png

我们还根据域名访问的流量,包体实际的用户量级, 按优先级去对我们的CDN域名进行划分,从优先级低的灰度至优先级高的,以保证灰度方案合乎我们的预期。

包体数据的一致性?

上面提到的域名灰度设计完了之后,业务上就要考虑如何做配合的问题,对于不同的包体,应该有不同的处理方式

image-2025-5-22_20-50-28.png

  • 域名属于原有云CDN的包体:待灰度包体,无需过多操作
  • 桶正在迁移,域名在灰度的包体:这部分包体需要进行双写处理,同一个包体要同时上传至火山云OSS和原有云OSS。这时候访问域名会按照设置的流量配比到分别的CDN进行回源;
  • 域名已经属于火山云CDN的包体:这部分包体即为灰度完成的包体,也无需过多操作

因此上述方案,可以认为对于迁移本身, 按照域名迁移。

对于打包程序本身,识别该包体对应的域名,进行该包体的单写或者双写处理。

对于这种方式处理的弊端是,在第一次对象存储迁移后,包体在灰度完之前都会是双份的;

对于双写后的数据一致性保障:我们通过事务来处理,任何一个对象存储上传失败,即可在前置条件进行拦截,后台显示CDN打包失败或者上传失败,此时流程跑不通,广告计划跑不通 。只有双写成功,该包体才能正常投放

出现异常情况的回滚?

对于异常情况下的回滚,其实可以做对应的分类

  • 若正在灰度的域名,遇到火山云CDN下载回源问题,将CDN域名流量切回原云即可,因为此时打包包体为双写,下载不会受到有影响
  • 对于已经灰度完成的域名,遇到火山云CDN下载回源问题,可以分两步回滚

    • 1,将CDN域名流量切回原有的云,并在原有的云设置回源至火山云对象存储即可
    • 2,在后台设置对应包体为单写到原来的云,重新打包处理,至此回滚完成。

因此,回滚问题也得到解决

CDN下载质量监控?

这快依赖于火山云大厂的天然集成优势,我们这块不用做过多的业务监控,只需要看对应的监控指标即可。

image-2025-5-22_0-18-42.png 另外,火山云还给我们提供了CDN日报的邮件发放,可谓是在早上上班边喝咖啡边检查邮件时,就能做到对应的CDN日常检查。

image-2025-5-22_21-32-13.png 通过这个质量监控,我们实际还意外的发现有CDN盗刷的情况存在,由于CDN流量采用是95带宽峰值的计算,我们可谓是狠狠的被刷了一波钱。这里可呼应前文的CDN的访问流量费用,这时候我们才发现,原来之前有很大一部分的CDN访问流量费用都是被刷出来的,可谓是哭笑不得了。

image-2025-5-22_21-45-29.png

针对这部分盗刷的情况,我们也做了对应的策略去做防刷处理,成本因此又降了一大部分。

总体灰度流程:

解决了上面那几个问题,我们灰度的流程就很明确了

1,针对某个域名,先进行一波该域名下,对应对象存储桶的全量包体的迁移

2,按域名,通过DNS分配对应的流量进行逐步灰度,并在后台设置对应的包体为双写

3,单个域名灰度完毕,设置对应的包体为单写到火山云,并进行下个域名的灰度

4,重复该流程,直到所有域名灰度完毕。

通过这个流程,我们的CDN迁移流程可谓是圆满完成了 image-2025-5-22_21-54-8.png

结果与展望

结果:成本的大幅度降低和可观测性的提高

从结果上而言,我们通过以上的一套组合拳,比我们预期节省50%的成本,还要好,我们最终节省了约82% 的成本(针对单个月而言)。

同时,我们可观测性也如上文所说,得益于火山云的监控,得到显著的提高,

展望:边缘节点动态打包?CDN的防刷?

1,对于目前很多云的CDN这块,其实他们都提供了一种根据链接参数,在边缘节点进行动态打包分包的策略。这块如果做了,我们就无需在对象存储中存放多个渠道的包体,仅需维护母包文件即可。通过这样的方式,能节省很多对象存储包体存储的成本

iShot_2025-05-25_17.14.54.png 2,对于CDN的防刷策略,其实是有非常多的。

  1. 限流:按IP、用户、资源等多维度限制访问频率。
  2. 名单:黑名单拦截恶意,白名单放行可信。
  3. 验证:验证码、JS挑战识别非正常请求。
  4. 行为分析:分析请求特征,结合AI识别异常流量。
  5. 动态策略:实时调整限流阈值,弹性封禁可疑IP。
  6. 防盗链:Referer校验、签名校验防止资源被盗用。
  7. 日志溯源:分析日志,定位异常流量来源。
  8. WAF防护:借助Web应用防火墙过滤恶意请求。

我们目前也是按照我们的自己的业务实际,去结合使用了这些防护策略,但目前而言还是会有防不胜防的情况,这东西比较类似于黑产对抗,需要持续的去做对抗这样子。

至于为什么CDN会被盗刷,我私认为鱼皮大大这篇文章,给到了我们很好的思路,如果有兴趣的同学也可以去阅读阅读。

juejin.cn/post/738990…

总之,软件工程是没有银弹的,作为系统迭代而言,我们还是有很多可以做滴,

最后,再附上37手游的Slogon: “创新点亮梦想,分享成就未来,相信创造奇迹”