3

《火箭联盟》首席工程师:如何实现100万同时在线、服务器不崩?

 1 year ago
source link: http://www.gamelook.com.cn/2022/05/482517
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

《火箭联盟》首席工程师:如何实现100万同时在线、服务器不崩?

2022-05-07 • 项目开发管理

【GameLook专稿,未经授权不得转载!】

GameLook报道/如今,免费模式已经成为了游戏业最主流的变现模式,它可以降低游戏门槛,大幅提升用户量。然而对于很多的主机来说,从付费转向免费并不容易,除了游戏运营方式的变化外,同样需要大量的后端支持工作。

在此前的GDC演讲中,Psyonix工作室首席在线服务工程师 Matthew Sanders讲述了《火箭联盟》从付费转向免费之后突破100万同时在线背后的后端支持,并详细谈到了Psyonix团队为此做出的努力。

以下是GameLook听译的完整内容:

Matthew Sanders:

lazy.png

我是Matthew Sanders,在Psyonix工作室担任首席在线服务工程师,之所以给出今天的分享,主要是因为我负责游戏转向免费模式的后端准备工作。

先来说说团队并快速了解我们遇到的问题到有多大,Psyonix的在线服务团队主要是做什么的?我们负责游戏相关的数据库、网页服务和一些网站,这包括一些研发活动和在线活动的执行。

什么是免费?就和听起来一样,《火箭联盟》要降价,目的是降低游戏门槛,让那些不想要付费玩游戏或者支付不起游戏购买费用的人能够体验到。

那么,对后端扩容支持更多玩家就可以了,不是吗?这个改变可能要求我们的后端支持更多的流量,自从2015年发布以来我们就很熟悉后端工作,所以免费模式的决策出来之后,我们就知道需要很大的工作量。

在今天分享的最后,我们会知道,经过了一年多的准备之后,用户流量的确出现了大幅增加,我们已经为此做好了准备,因此保证了比较成功的重新发布。

lazy.png

今天的内容主要分为3个部分,我们会提到规划和准备,其中包括新的合作关系、需要做的分析以及负载测试,第二部分我们会更细节了解规模化提升,最后,我们会分享发布经验以及自此之后的新常态。

一、规划与准备

我们做了大量的规划和准备,它们占据了我们大量的时间,但这里只分享其中一些部分。

lazy.png

首先,我们的分析主要是围绕我们可以预期的是什么,我们用了一些时间研究负载预计以了解可能会见到多大的用户规模,还对架构进行了分析,以支持潜在问题。

接下来的合作关系部分更值得讨论,我们有一些支持外包,从简单的票务支持到与更紧密的发布支持工作,最后我们会谈到负载测试以及它是如何适应这个项目的。

1.分析

通过转向免费,我们会带来多少新玩家?看起来似乎很难用占卜的方式得到结果,但有些技巧可以预测,最好的方式之一就是找一个与你类似的游戏发布之后的情况。不幸的是,《火箭联盟》是一个跨多个主机平台的火箭主题游戏,所以想找到参照物很难。

lazy.png

最后,我们决定把支持的玩家数定到现有用户的3-5倍,我们将预测数据的上限作为负载测试标准,对于负载测试,我们稍后会提及更多。

lazy.png

接下来是架构评估,我们该如何预测架构需求呢?我们将不同部分进行拆分,然后看每一个部分做扩容设计之后的风险,然后为这些风险做backlog,做表单的时候,我们主要针对连贯性和预览设计,这个文档实际上成为了复用性很高的材料,我们还给每个表单增加了peer review,我们给大多数的应用商店DLC都做了peer review,包括文档也没例外,我们还对源控制做了审核,以便让我们所有的产品都可以做预览。

每个部件的评估都是非常直接的,但我们用了一些时间才把架构评估做完,因为有很多的组件。

2.合作关系

lazy.png

一开始的时候,我们就确定想要最好的外部支持,我们内部并不没有大量的工程师员工,所以我们希望寻找这方面的专家。我们发现外部专家的成本比内部员工高很多,但我们的想法是,如果他们可以让项目研发不停下来,那么后来的收入可以弥补这部分的开支。

我们商谈的第一家合作厂商就是谷歌,我们的游戏一直都在谷歌云平台(Google Cloud Platform,GCP)上运行,所以已经有了支持关系并签订了合同,即使如此,我们在做了评估之后还是决定使用他们更多的工具,比如CRE(Customer Reliability Engineering)和GTLA(Game Title Launch Assist)。

接下来,我们希望通过一些专业工具增强内部团队,PERCONA是MySQL方面的专家,所以用他们的支持服务是有意义的,特别是我们使用了PERCONA服务器。

Redislabs是新工具,我们在运行一些redis cluster,但没有正式的支持,我们联系了Redislabs并写信请他们报价,这需要额外的支持,但抵消了GCP很多的管理负担,与这样的公司合作就像是买保险,可以让我们在游戏发布期间最大化降低可能出现的故障率,与此同时,也给规划和研发阶段的提升带来了珍贵的机会。

lazy.png

我们很快充分利用了既有的支持合作关系,并用不同的合作来解决对应的问题。比如premortem,它类似于postmortem,但更具有预测性,并让他们分享工具使用技巧。谷歌提供的另一个支持是资源规划与分配,我们不是一款新游戏发布,所以在资源使用方面已经有确定的使用数据,包括不同GCP服务使用的CPU核心、内存以及硬盘。

之前提到过,我们预测的发布期间用户量可能是现有用户的5倍,这些资源规划从两个方面带来了帮助,首先是提前获得了配额提升,其次是可以让GCP为我们的扩容预留足够的硬件。在云服务时代,硬件使用同样是不容忽视的,因为把规模扩容五倍,同样会给硬件带来压力。

除了谷歌之外,我们还与Redis Labs讨论了很多,甚至在正式使用他们企业服务之前就进行了多次技术方面的问答,了解他们可以提供的具体优势,随后他们还给我们的数据库迁移提供了支持。

3.负载测试

lazy.png

这是我们发布过程最重要的环节,而且是玩家不会遇到的功能。我们最初的计划是用它作为一个调研工具,看带来了什么提升,但最终它带来了更多的用途,也是最被低估的功能。

lazy.png

负载测试是比较独特的,所以我们几乎没有使用任何现有的代码库,负载测试代价也比较昂贵。最后,负载测试很难做好,因为它既需要大量的研究,还需要很多次迭代才能得到正确的客户端请求模拟,包括请求频率和请求等待时间。这些都清楚之后,我们很快将负载测试作为主要聚焦点之一。

我们已经有一些工程师专门做locust,现在为负载测试投入了更多,在众多的框架当中,我们选择了web sockets,另外,运行Kubernetes也给我们带来了很多的帮助。唯一的不便就是,它是用Python写的,而我们使用的服务很少使用Python。

随着测试规模的增加,我们在考虑要不要做一个新代码库,我们发现最初的压测并不协调,只是对测试运行生成随机数据,造成了差异化很大的数据,原因可能在于,每个请求完成的工作可能是完全不同的,比如有些请求甚至不经过我们的数据库。

我们的解决方案是写一个新的代码库以协调测试数据,locust会自动注册和一些其他行为,还有些会匹配真实玩家行为。因此我们需要用户提供ID和其他信息,以更精准提供服务。

lazy.png

另外一个需要说的是,运行负载测试是非常耗时间的,首先是因为测试需要的时间远超过你的预期,另外一个则是测试运行比例,比如我们需要运行100万个locus,但稳定运行每秒只有几千个,简单计算就需要数分钟,这对于一次测试来说太耗时间了,我们该怎么办?

我们可以确定测试需要的总时间,但这需要更长的工程时间和研发时间,我们愿意付出时间成本,因为大多数的locus客户端运行在云端,而且也是更真实的,更快速的测试会让这些结果不那么真实。

另一个比较耗时的是运行时间(run time),一旦全规模运行测试之后,到底是立即决定是否通过,还是让它多运行一会儿?考虑到关断时间,我们更倾向于后者。更长的运行时间可以发现一些不那么明显的问题,比如资源使用峰值,更长的运行时间还可以让我们看到更多的测试组合,扩容时间和运行时间组成了一次测试迭代,随着多次迭代,需要的时间大幅增加,这对我们的测试带来了很大的帮助,但也耗费了大量的时间。

lazy.png

谈到测试,迭代其中一部分目标就是收集结果,比如HTTP相应代码、服务日志。获得了这些数据之后,我们该如何确定得到的结果是精确的呢?我们对客户端的模拟有多精准?我们研究了真实的客户端请求,真正比较大的差异可能是真实客户端会发出数百个请求,使得我们没办法全部模拟,相反,精准模拟让我们可以看到哪些功能在扩容方面有风险,这导致了大量的后续修补。

lazy.png

Locus负载测试的未来是怎么样的?我们决定在发布之前继续测试,对于服务局限来说,哪怕是最后一分钟,你知道了也是好的,你至少可以减轻它带来的影响。除了发布之外,我们觉得负载测试应该拓展到所有的SDLC当中,一旦扩容,我们可以发现所有的性能问题。

游戏的变化可能会带来更多的不确定,但持续测试可以让我们对自己的服务更有信心。

二、扩容改善

这是占据了我们大部分研发时间的地方,第一部分内容谈到了我们的规划和准备工作,这部分主要从细节方面谈如何执行。

lazy.png

首先,我们将核心服务从Google AppEngine迁移到了Kubernetes;其次,我们改造了匹配功能;第三,我们将所有的Redis数据都迁移到了Redis Enterprise;第四,对我们的MySQL做了一些提升;第五,我们增加了Web Service速率限制系统;最后,我们会用一些时间做这部分的研发复盘。

1.将核心服务迁移到Kubernetes

lazy.png

前面提到,我们将核心服务从Google AppEngine(GAE)转移到了Google Kubernetes Engine(GKE)GAE是谷歌的平台即服务,只需要将你的peer传到平台,服务会接管一切。GKE只是谷歌管理的Kubernetes服务,我们从2015年发布之初就一直在使用GAE,我们迁移到GKE是有一些目标的,可以对PHP runtime有更多的控制,还需要对资源扩容有更多的控制。

另一个目标是更多的部署连贯性,并将更多的组件在Kubernetes运行,它还解决了云服务器的一些不可知问题。

还有一个部分是将GCP方案分离开来,一个GCP方案是区分GCP资源非常高层次的结构,它在不同环境的使用都是不一样的,使用分离的GCP方案可以让每个方案使用的资源更清晰。

最后,负载测试也是不可或缺的。GKE对于我们的小团队来说依然是新鲜的,因为我们的使用经验仅包括迁移服务,这时候GCP团队的帮助非常及时,因为他们可以从平台方面帮助我们做负载测试,并根据他们在Kubernetes方面的经验给我们建议。

完成到Kubernetes的迁移是将我们的核心服务现代化的基础工作,也是让游戏转向免费模式扩容的基础。

2.改造匹配功能

lazy.png

我们做的第二件事是改造匹配功能,最初的匹配有一些已知的性能问题,这些问题并不影响匹配正确性,但会限制性能天花板。为了解决这些问题,我们知道需要做些新东西,而且这会比较复杂,因为《火箭联盟》的匹配有很多复杂的规则。

我们的匹配服务是单线程.NET应用,已经很接近最大化状态,离我们需要的扩容目标相差很远,而且包含大量没有头绪的代码。

lazy.png

那么,我们该怎么做?我们要保留所有的基础功能,但同时要满足游戏扩容的需求。最明显的解决方案似乎是MapReduce,我们从一开始就考虑过它,但我们还发现了OpenMatch,经过大量的调研之后,我们选择了后者,虽然看起来需要大量的框架研发,但也可以在功能方面带来大量的自由度,而且它还是开源的。

与我们的匹配服务不同的是,OpenMatch就是为扩容设计的,与原来无头绪的代码比起来有了很大的提升,而且它是尖端的技术,至今还在预发布阶段。

当然,最后我们也进行了负载测试,对匹配功能进行测试是必要的,我们将OpenMatch在GKE当中调试,就像是核心服务那样。更重要的是,我们学到了微妙的变化是如何影响整个匹配体验的。匹配机制的改造耗时一年多,但这个投入是值得的,对我们的免费发布很重要。

3.迁移到Redis Enterprise

lazy.png

在我们看来,Redis Enterprise最好用的地方就是,它是完全自动re-sharding的,这意味着我们可以增加cluster规模,但需要的点击更少,因为数据库之间的跳转是自动的,我们在免费发布的时候使用了这个工具。需要注意的是,这需要牺牲一些性能。

lazy.png

使用Redis Enterprise的过程中,我们还学到了很多东西,尤其是不同的代理设置。最左侧是大多数的代理配置,你只需要一个代理,因为这是性能最高的方案。然而,考虑到我们的数据库很大,我们需要保证性能的连贯性。

我们最初选择了OSS Cluster模式,这是最简单的改变,但不幸的是我们最后却没能用到它,因为缺乏足够的支持,而且我们在Redis客户端library的经验不多。相反,我们使用了右侧的DNS Load Balancer,虽然有一些限制,但它用起来还好。

使用了Enterprise之后,我们知道自己的数据库有些是不好用的,我们做调整的原因,主要是希望提升指令的可观察性,衡量Redis性能是多少有些困难的,直接衡量CPU行不通,衡量每秒运营次数也是有误导性的。

lazy.png

可观察性的改变,让我们看到了性能问题的答案,然后对cluster扩容。同样重要的是可以监控数据库。搞定了这些之后,它比很多开源项目都更有效率。这张图右侧展示了每秒读写读写,这是dashboard上众多的图表之一。

Redis Enterprise还有一些优势,它在处理Pub/Sub优化方面比开源工具好很多,但最主要的是它不会把所有publication分配给所有shards。其次,Redis Enterprise可以临时复制,而且不会干预production cluster。

最后,我们使用Enterprise做的这一切并不会导致我们被锁在Redis Labs一家供应商身上,唯一的风险,可能是你不希望离开他们的服务。

3.MySQL提升

lazy.png

除了Redis,我们其他的主要数据库都是MySQL,很长时间以来,它都是我们的扩容瓶颈,特别是它只能纵向扩容,带来了很大的性能消耗。

这些年来,我们最好的选择是Feature Shards,它将一系列的表格迁移到了新服务器上,而且做起来是非常简单的。不幸的是,它不能解决纵向扩容问题,所以多年的使用之后,很多表单如果不投入大量的努力,几乎很难分离出来,不过它给我们大量的功能都带来了帮助。尽管有扩容风险,但我们最后认为没有足够的时间最横向扩容,我们还用它解决了一些新问题,最后实现了负载测试目标。

lazy.png

但这不是我们唯一的MySQL提升,我们还使用了ProxySQL,能够按照需求扩容,每个ProxySQL都与我们的MySQL数据库相连,我们还获得了Instant failovers,我们之前的方案需要50秒钟,这是不可接受的,所以它只在紧急情况和维护窗口使用。

Proxy SQL给我们带来了动态化的query routing,是紧急扩容非常好用的工具,而且不需要调整我们的服务。但也有一些不利,比如一些bug会导致停止,而且Proxy SQL有些复杂,学习曲线加上我们的经验不足,导致在免费发布几天内出现了一些配置错误。这也是尽早做主要功能的原因之一。

总的来说,Proxy SQL绝对是个提升,我们只是在使用了一段时候讨论它的不足,但带来的优势远远更多。

4.速率限制

lazy.png

最后一个是非常小的功能,也就是速率限制。这个功能是怎么来的?最初,我们希望把它作为一个登陆队列,这需要大量的工程投入,最后通过理解玩家人数级别、游戏次数速率和玩家流失之间的关系,我们选择了一个更简单的方案。

我不希望投入大量的时间做登陆队列功能,主要是它很少被使用,所以我们选择了相对简单的定制化方案,能够集成到我们的基础设施当中,速率限制成为了我们用途最多而且最有用的功能之一,我们可以限制任何服务,还可以对全局或者每个玩家的呼叫作出限制。比如,我们可以将总体游戏局数限制到每秒500次以控制用户量的增长,如果我们看到了客户端bug,还可以限制好友邀请为每秒一次。

5.研发复盘

lazy.png

随着我们的功能研发进入了尾声,我们发现并没有实现想要的那么多功能,那么多月的时间都用在哪儿了?不要害怕提这些问题,并且给出答案。

第一个原因是,我们和很多的游戏研发团队一样,因为疫情的影响从全职研发转向了居家工作。其次,很多主要功能需要大量的投入,但我们团队并不是所有人都参与了所有SDLC的研发,在线服务是需要回滚计划的。

需要注意的是,不要过度分析,我们很多的功能都是没有时间做,然后就是给出合适的截止日期,确定并尊重这个决定,并且根据它来协调研发。确保团队买账,如果真实的截止日期是发布当天,如果你把截止日期提前很多会让人接受不了,转向免费之后,我们的很多重要功能都是在发布前需要完成的,所以《火箭联盟》的截止日期安排并不够好,而且2020年之后的疫情也导致团队协调不是那么顺畅。

三、发布心得

lazy.png

这部分我们只讨论发布本身,首先来看看发布规划,提前一周发布游戏更新,为了让玩家更快速上手,我们选择将一些功能提前发布,其中一个是Epic账户与游戏帐户的连接,这是个很复杂的功能,提前发布可以让我们在大量用户涌入之前进行测试与监控,也可以帮助免费发布前一天进行热更新。发布日期选择的是周三,与平时周末相比不是那么忙。

lazy.png

接下来是发布,这张图展示了游戏更新、热更新与免费发布之后的用户量变化,我们是首次看到《火箭联盟》同时在线用户超过了100万人,这是个很大的里程碑记录,但实现之后更像是提前预测过的结论,因为我们的负载测试显示,性能天花板比这个数字更高。

周日迎来了用户峰值,超过了我们五倍用户量的预测,但还没有超过我们负载测试实现的最高值,这意味着你在发布之前都需要一直进行测试,也显示了为什么在周三发布是非常不错的选择。

lazy.png

如果仔细观察,我们会发现游戏发布并不是一帆风顺的,如图所示,我们遇到了一些比较严重的问题,也经历过非常大的用户量下滑。第一个问题出现在发布当天,我们的账户链接功能出现了问题,主要是因为这个功能处于两个公司之间,我们在负载测试的时候是无法进行的,需要注意的是,这个功能是提前一周发布的,所以这向我们展示了免费之后的用户量更大。

第二个问题出现在周四,我们的Redis Enterprise re-sharding原本只是个预防措施,但我们的数据库承压很大,导致了一些功能暂时停掉。第三个问题出现在周五,它并没有出现在图表上,因为并不影响玩家数量,这就是我之前提到的Proxy SQL问题,主要是配置错误。到了周末的时候,虽然用户量级更大,但我们再没有遇到特别严重的问题。

对于发布首个周末来说,我们实现了非常不错的结果,但团队的感觉是怎样呢?

lazy.png

我们的团队很紧张但也很有信心,同时在线用户峰值每天都在刷出新高,达到了我们预测的5倍量级,首周之后,整个团队都加入了“战时”视频会议房间,我们做的准备比之前任何一次发布都重组,但依然在调节方面非常紧张,因为你很难在负载测试阶段发现所有问题。最后需要说的是,虽然没有比较大的故障,并不意味着我们就可以忽略一些小问题。随着用户量在周一回落,我们的团队可以有时间对新常态思考更多。

lazy.png

进入2021年之后,《火箭联盟》 的用户量依然在增长,而且依旧是之前常态用户量的3倍,这种情况下,我们的服务对性能问题更加敏感,包括代码以及配置的变化,比如我们的一次活动提高了玩家的奖励,结果导致性能被压榨到了极限,好的一方面是,这不仅可以给我们的活动做测试,还可以用于任何负载测试。

最后,我们更新了最佳做事方式,包括设计在线迁移,推出改变以及始终拥有一个回滚计划。

四、总结

那么,你们可以从今天的分享得到什么?

lazy.png

这是我的建议,尽早寻求支持和建议,你可以做长期计划,但不要过度规划,为其设定一个截止日期。今天非常重要的一个话题就是负载测试,这是非常困难但也极其重要的环节,我们以后还会做负载测试。

当你做重大功能的时候,要考虑它的截止日期并做出协调,尊重这些截止日期。最后,你应该做一些多功能的控制方案,比如速率限制,它需要的工作量不大,但可以多次复用。

如若转载,请注明出处:http://www.gamelook.com.cn/2022/05/482517


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK