开发者分享:网络游戏避免上线炸服的10个方法

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

GameLook报道/对于所有的网络游戏玩家和开发者来说,发布当天都是一次“大考”。通常情况下,无论是通过营销手段还是口碑传播,很多网络游戏发布当天都会涌入大量玩家,而如果开发者没有对此作足够的准备,就很容易“翻车”,导致服务器崩溃,玩家大量流失。

对于网络游戏开发者来说,怎么做才能保证游戏发布的成功呢?在GDC 2022演讲中,来自Pragma Platform Inc公司的CTO Chris Cobb分享了游戏发布当天常见的10个陷阱,并对应给出了解决方案。

以下是Gamelook听译的全部内容:

Chris Cobb:

今天我们主要分享在游戏发布当天把服务器搞崩溃的10种方式,会说一些故事和案例,我是Chris Cobb,担任Pragma公司CTO,Pragma是一个提供在线游戏服务的平台,比如跨平台账号登录、游戏匹配等方面。

我们与全球顶级游戏有合作,包括《英雄联盟》、《命运2》,手游平台有《植物大战僵尸》等。今天我们主要谈的是游戏发布当天可能会出问题的方式。

很多人都经历过这样的问题,这些问题都非常熟悉,不管是开发者还是玩家,都会在游戏发布当天遭遇服务器崩溃或者无法进入游戏的情况,通常情况下这些问题都是由后端支持平台导致,之所以这个问题非常重要,是因为,当玩家们在发布当天遇到服务器问题之后,他们第二天回到游戏里的可能性是未知的。

虽然很难得到确切数字,但至少有60%-70%的玩家如果在发布当天不能玩游戏,他们是不愿意再碰这款游戏的,因此发布当天的服务器稳定性是非常重要的。所以,我们基本上就是分享一些错误的做法,然后分析我们可以对此做些什么。

网络游戏最重要的话题

对于网络游戏来说,最重要的是避免灾难性的错误。第一个主题就是尽早开始,如果把问题拖到研发后期,可能会需要几个月的时间才会解决,如果直到研发最后几个月才测试多人模式,那显然是行不通的。有时候一个项目的研发可能会持续好几年,所以在研发开始的时候解决远比等到截止日期临近好得多。

如果你的工作室转向在线服务,比如季节性的活动、Battle Pass,每周发布一次更新遇到的问题,与每年才会遇到一次的DLC问题不同,比如《命运》或者《火箭联盟》这样经常更新内容的网络游戏,你不能将玩家数据简单的存在服务器上,给游戏打一个补丁然后离开。

你需要考虑的是,如何随着时间不断优化数据,快速在不同版本之间移植数据也是一个挑战,幸运的是,你可以在游戏上线之前进行测试,否则玩家就会成为你的首批测试者。这时候我们就会看到玩家们丢失排位数据、已经获得的内容,比如一个补丁之后,玩家们的账号甚至都被删除,所以尽早开始。

第二个主题是衡量,如果你都没办法观察问题,那就更不用提衡量和解决问题,所以我们需要收集相关功能的数据,通常这分为两个方面,包括总体以及在线运营,比如服务是否能够运行,是否有必备的技术,但我们也需要关注游戏健康度,比如玩家与游戏的互动如何,所以数据是我们找到游戏运行问题的一个方法。

我中途加入了一个团队,他们正在准备发布一个比较大的功能,他们加班到了凌晨三点。第二天早上的时候,我随口问了句这个功能的表现如何,团队里的其他人有些懵懂,然后回答说,应该还可以,目前还没有玩家对这个功能公开提出批评。作为专业人士,这样的结果是不行的,如果等玩家们都开始批评,那时候发现问题就已经晚了。

还有一点是,不要单独解决这个问题,经验是最好的老师,如果你能找到在发布当天遇到过服务器问题的同行,这可能会给你带来帮助。

发布当天让服务器崩溃的10种方法

第一步,没有打造登录序列

游戏发布当天会迎来最多的玩家数量,可能是平均玩家数量的10倍甚至更高,所以这是个流量问题,你的问题并不是解决常规问题,而是当所有人都同时登录的时候该怎么办。比如洛杉矶市区,如果是夜间11点驾车,那是没有问题的,但如果是下午5-7点,简直是噩梦,这对游戏来说简直是灾难。

第一个案例实际上来自于Niantic的《Pokemon Go》,他们曾公开多次分享发布当天遇到的服务器问题,我也曾经在街上玩这款游戏的时候重新加载过几十次。实际上,他们已经发布过在线游戏,《Ingress》也取得过不错的成功,但《Pokemon Go》的用户量比上一款游戏峰值用户的50倍还多。

人们很喜欢抓精灵,这款游戏发布当天遇到了比之前游戏多50倍以上的玩家,但问题在于,他们没有预测到能有这么多玩家,所以没有做登录序列,因此,他们也不知道一次能够体验游戏的用户有多少人。他们没有对此做足够的预案,当一批玩家离开之后,还会有大批玩家接踵而至,所以服务器问题重复发生。

所以,如果你预计发布当天会迎来大量玩家,最好是做一个登录序列,以保证玩家的游戏体验。我们的目标是保护发布当天的顺利,所以就要给预测的用户量预备足够的支持,为此做一个登录序列,但这也带来了第二个问题。

第二步,打造错误的登录序列

不知道为什么,但我觉得大部分的登录序列一开始都是不好用的。我们打造了登录序列,但总会处于不同原因发生问题,就像是我们去机场安检,总会遇到我们不希望看到的排队长龙。

很多时候,我们遇到了问题,并为此打造了登录序列,但上线之后还是失败,这到底是什么原因呢?设计登录序列的时候,我们考虑的是必须限制玩家登录,有时候可能是阻止垃圾账号,包括空白账号,你总会遇到各种现象。

作为开发者,我们在做登录序列的时候就会考虑,我们需要加入什么条件,才能让甄别真实的玩家,就像是参加GDC需要先排队再进门,这是行不通的。我不会展示背后的原因,因为这是个复杂的技术,但会支持一些问题。

你首先需要计算一次允许进入游戏的人数,比如你一次只能支持10万名玩家,你就要为此设计登录序列以保护玩家体验,就像是要计算CCU。另外一个比较容易忽视的问题是,你忘记了计算允许他们进入游戏需要的时间,就像是迪士尼乐园早晨开门,你会遇到很多人,但并不能一次让所有人都进去。

因此设计登录序列的时候,你既需要设计同时进入游戏的玩家人数,还需要了解玩家总数在什么范围,所以,我们需要限制同时玩游戏的用户总量以保持玩家们登录顺利,所以在授权玩家登录之前,你需要搞清楚这个服务的用意。

第三步,没有对平台进行负载测试

当然,你可能做过负载测试,也就是发布当天用真实玩家进行测试,然而这并不是一群非常友好的测试者。我记得一个比较大的发行商在公开测试周末之后发布过一个博客,说他们的服务器一直崩溃,一个好朋友问,为什么不准备足够多的服务器以支撑如此之多的玩家数量呢?这是一个令人很难回答的尴尬问题。

为了不重复,我们简单说一下,你通常会在发布当天遇到更多的玩家数量,所以你的服务器无法满足当时的用户需求,一旦有用户离开,你准备的服务器可能就够用了。

这是个复杂的问题,你测试的目标是想知道发布当天的真实用户压力,我们的目标当然是证明能够支持多少玩家体验游戏。曾有业内大神说过,所有模型都是错的,但其中有些是有用的。

所以,负载测试的目标就是找到一个有用的模式。这里有几种场景,首先是负载测试就是实际发布当天的用户量,最完美的方式就是用真实的玩家数量进行负载测试,然后找到问题有针对性地解决,但你无法提前进行。

因此,你需要模拟发布当天玩家进入游戏的场景,他们到什么地方、访问了商店里的什么东西、通过了哪些玩法。你实际上希望模拟真实用户的游戏内行为,然后在复杂测试中进行规模化扩容。

我们不能通过单个API请求进行模拟就把它运用到50万用户的场景下,你想要打造的是一个有用的模式,想知道玩家们可能会怎么行动,而不是认为他们都做同样的行为。

另一个是负载测试环境,它必须与你的研发环境适应,这包括安全问题、资源等多个方面,你需要提供数据库备份、硬件准备,所有的东西都需要在负载测试的时候齐备。但我们该怎么做到呢?你想要基础设施像写代码那么简单,但实际上每个基础设施都有不同的菜单和控制台,你不可能在另一个环境中完全复制。

你可能会遇到这样的情况,理论上负载测试没有问题,但会因为配置而遇到错误。你不会想要走捷径,因为这和很多至关重要的方面有关。

做《英雄联盟》项目的时候,我们做了并行数据中心追踪一切情况,甚至还有负载测试2,但有时候我们有很多事情要忙,完全把负载测试2给忘记了。有一天我问技术总监,负载测试1怎么样?但他回答说,负载测试1在哪里?最后的结果是,我们不知道在哪个地方丢失了数据中心,实际上我们失去了对整个环境的控制。有时候事情就是如此诡异,管理如此之多的环境非常具有挑战性。

因此我们不得不重新做负载测试2,这浪费了很多时间。所以,你必须对每一个制作环节保持关注,就像是真正的游戏运营一样。尽管最终我们还是解决了问题,但依然是比较具有警示性的。

我们的目标是对准制作环境进行压力测试,不要忽略你在测试过程中对配置做出的任何改动,不要丢掉对测试环境的追踪,因为它有可能代表了你的真实玩家行为。

第四步,做了太多问卷

这是个很普遍的问题,在游戏开始做预测的时候,我们往往会做一些问卷调查,这样做是非常不错的开始方式,你想要做更好的UI,想设计更好的体验,于是你在想,我们最好是呼叫服务器以防某些东西变化。随着时间的变化,这种方法可能是有问题的,因为这就像是呼叫调查。

另一个与《英雄联盟》相关的案例是,我们有工具可以向玩家发送消息,如果有一个服务停掉,他们就可以通过这个工具知道发生了什么,所以你可以直接在某一个区域向50万人直接发送一条信息。

但有一次我们发送了信息之后,再次收到大量玩家请求,试了很多次都是如此。我们在想,到底哪里出了问题?实际上这个功能本身没有问题,但出于某些原因,在玩家收到信息之后,我们的设计是30秒钟之后重置计时器,所以很多是重复呼叫,突然之间,我们设计了一个攻击自己服务的bug。

调查问卷现象是经常会遇到的,这种情况下你尤其需要与工程团队协调,你不能认为只有一个客户端,进而只模拟一对一的网络呼叫,你要设想有100万个客户端,他们每个人都会进行呼叫,这某种程度上需要你改变思考问题的方式。你需要避免这样的问题,因为随着游戏增长,你会遇到大问题。

我们的建议是保持Socket开放,这样你的服务器可以直接给用户发送信息,这样可以带来非常有效的反馈,每次遇到问题的时候,玩家们就会知道发生了什么,但你并不需要每隔几秒就呼叫服务器看发生了什么变化。这样,你就只需要在问题发生的时候才去解决,以打造可以扩容的平台。

所以,对于呼叫服务器,我们应该谨慎使用。

第五步,没有做数据库分片(database sharding)

如果说希望你们从今天的分享中得到什么,这一条我认为是最需要关注的。不知道是什么原因,但很多工程师并不愿意说数据库分片的问题,传统来说,对于很多中小团队,我们没有做数据库分片的技术和资源,但如今支持新硬件比以往更加容易,因此我鼓励同行们尽早在研发中考虑该问题。

单一的数据库会给你带来非常大的瓶颈,即便是扩展了网络服务器,如果所有人同时使用数据库,同样会给你的系统带来很大的压力。这是需要注意的很重要的问题,也是最可能导致游戏崩溃的一个原因。比如此前说到的玩家账号问题之外,用户背包也会给你带来问题。

我们这里可以有多种方式来解决,其中一个就是数据库分片,比如把数据库一分为四,每个分片存储25%的玩家数据,这是个很好的开始方式。还有一个方法是在你的数据库内进行分隔,假设你的游戏有背包、进度、任务和目标,还有Battle Pass、季票等,很容易用一个Jsonclub来存储关键数据。

项目一开始的时候,这是没有问题的,因为那时候你需要存储的数据还比较少,哪怕是内部测试扩大到100人,这个方法也还是有效的。然而在发布当天,这可能是行不通的,即便是当天只有测试期间同样多的用户,把它们分成小组也是有用的。

比如,网络更擅长传输很多小的数据量,而不是庞大的数据。另外,如果你将背包和重新装载分开,意味着你每次发送的数据量就会少很多。玩家购买东西,你只需要处理背包问题,而不需要同时传输很多并没有发生变化的东西。

Pragma合作的很多客户都是大作游戏开发商,他们通常与发行商有协议,在发布当天会有数十万甚至百万用户登陆,我们只有几个月的时间解决所有问题。好消息是,他们都有做登录序列,他们有负载测试,这都是很好,但他们负载测试登录序列的上限是4万人,他们在这个问题上卡住很久。

通过与他们的架构师聊天,我们发现了两个问题。第一个是,他们为所有服务器设计的都是单一的数据库服务器,包括账号、登陆、玩家数据等等,所有数据都打包在一个巨大的方块内。

所以,我们发布当天会有30万用户登陆,发布之后一周会有100万玩家。经过了多次衡量之后,我们决定在工程方面,只做数据库分片,首先是将数据库分割,仅这一个措施就让制作过程中可以保障22万玩家稳定体验游戏,加上登录序列授权,很快就解决了这个问题。

总结来说,你需要分割数据来解锁扩容能力,这样做可以从根本上改变你的平台特性。

第六步,有太多的微型服务

这可能与列表上所有的问题都不一样,尤其是在大公司当中,团队某个部门的一个bug就可能给所有人带来问题,所以你需要解决所有问题,这就很麻烦,所以,让某个团队专门解决某些问题是比较高效率的。

不过,如果走太远,这个方法可能行不通,首先你要先知道,如果对其他服务器的呼叫失败了怎么办?我们之前的想法是,所有服务器都是独立的,每个服务器都可以相应其他服务器的请求,哪怕其他服务器没有响应,你也可以继续自己的服务。

但问题是,如果你的呼叫失败了呢?在游戏里,我们实际上只有一个基础生态系统让玩家体验,通常来说,你并不会控制向其他服务器发送的无效请求,你只想获得需要的数据进行服务,所以不同服务之间是相互影响的。如果一刀切的方式管理太多的微型服务,就会将问题复杂化,通常情况下,一个关键服务挂掉,也会影响其他服务。

这将带来噩梦,每个服务都会优先考虑如何让他们的服务运行,这就会导致大量不同的环境,我碰到过一种情况,有个朋友说,服务器宕机不是他的问题,而是其他服务导致了游戏崩溃,结果每个服务都给出了同样的说法。

这很有趣,但我们都应该知道我们的服务是如何运作的,有太多微型服务经常发生的事,就是一个服务出了问题,就会带来连锁反应。我们想要保持规模,但同时也要目标清晰,在不同服务之间到一个分界线是很有必要的,这样,你就很容易看到某个问题发生在哪个环节。

通常来说5-10个服务就已经让你的团队疲于奔命,如果是20个以上的服务,你会发现很多东西都无迹可寻。

第七步,没有做数据缓存

数据库是一个很有价值的东西,但做数据库比很多方面都慢,缓存就是把我们的数据放在一些更快的位置,让它更容易被获取。

我们与第三方网站合作的时候,很常见的是,他们会在粉丝站创造很多测试账户,这些账户都是机器人,他们试图做出玩家数据,基本来说,我们觉得这是不错的。但问题是,每过几个月我们都会遇到问题,尤其是新的平台进来之后,如果所有的存储都被这些测试账户占用,那么真正的用户就可能会遇到问题。

随后,我们为第三方服务专门做了一个API,做一个所有这些玩家数据的缓存副本,所以,第三方服务可以自行迭代这些数据,它们的变化很慢,这样做让我们避免了服务器崩溃,最终让我们和所有第三都很满意。

我们希望保护自己的数据库,但这就带来了下一个问题:

第八步,使用太多缓存

如我们刚讨论的那样,缓存可以是个很好的工具,但有些时候我们会做过头。如果缓存太多数据,你自己甚至都不清楚某些数据是否已经过时,唯一的方式就是回到数据库验证。但由于优化的东西太多,你会逐渐失去控制,不知道哪些数据来自哪里,让你的团队很难不产生bug的情况下做出改动。

在与一个工作室合作的时候,接入我们的服务之前都很正常,但接入我们的服务之后,他们的服务器发生了崩溃,与之相伴的是,它还摧毁了一些关键服务,比如支付方式处理,这是很奇怪的,我们的服务与支付没有任何关系。

经过我们的调查,我们的服务每秒只发出10-15次请求,对于这样的游戏来说并不是很多。进一步调查之后发现,他们的很多服务实际上没必要做那么大的规模,大量的缓存占据了很多流量,这种情况下,我们共享了支付基础设施服务,就是这么两个毫不相关的服务,给我们带来了很大的痛苦。

我们与他们的团队沟通,比如为什么有这么多的服务,他们给出的理由是为了扩容准备,经过深度挖掘,我们发现团队做了太多的东西,以至于他们自己都无法全部追踪,所以,最后的解决方案是删掉了很多东西,只留了90%的代码。

因此,我们的目标是,你应该衡量和评估优化方案,不要猜测,你很难知道自己做出的改变会带来什么影响。如果你没有某个东西,最好是做一些数据收集工作。这是个很大的话题,但我要长话短说,你要首先问自己,这个功能发布之后,我想要的是什么?通过一系列的问题,找到最能够回答这些问题的答案,然后有选择性的收集数据。

否则,你会遭遇到大量数据,没有人知道这些数据是做什么的、来自哪里、用于什么目的,这会给随后的优化带来非常高的复杂度。

第九步,使用了最新科技

很多人可能知道,项目往往会被推迟,你的游戏可能会因为实用新技术而跳票数月甚至数年。Pragma的原则是,只选择那些有趋势性的技术。

我们合作过一个项目,它所有的匹配都是发生在客户端之外某个平台,一旦这个平台出错,玩家们的客户端也会遇到大量问题,玩家们一直抱怨。我们发现很多技术都是过时的,所以提了一个想法,就是用现代化的技术。

我们希望给玩家带来更好的体验,我们最初的设想是5名工程师耗时几个月完成。但这项目持续了4年,最终用了200人团队来做。发布当天,游戏体验非常粗糙,甚至有些玩家无法进行游戏。性能方面,与我们最初的愿望背道而驰,使用了更多的内存和CPU。

另外是开发者体验,这两个系统实际上使用了完全不同的两个编程语言,你需要切换全新的技术堆栈、研发环境、编程语言,这样才能完成。这是非常极端的案例,最终比我们预期的成本高了100多倍。

分享这个故事的目的是,有时候用新技术取代老技术是没错的,但你需要认真衡量,有时候新技术的代价非常高,当你解决发布当天问题的时候,你必须问自己,最优先的是什么。我们的建议是,使用一些经过规模化验证的技术,这对于游戏发布是很重要的。

比如在Pragma,我们使用的是Java,而很多大公司使用的是MySQL,可能所有人都没有想到,在2022年的今天,很多人还在用1990年代的技术。然而在游戏发布降低风险方面,使用成熟的技术可以带来很大的帮助。

很多工作室的内部工具都是尝试新技术最好的试验田,但当你做游戏发布支持的时候,最好是使用被证明过的技术,这可以让你的游戏发布更成功。

第十步:所有功能植入两次

这里我们说两个现象,一是不断重写功能,还有一个是在代码库里对同一个功能有多种呈现方式。这样的代码库很难维护,会导致很多质量问题,还会影响服务器扩容。我们都知道简单就是最好的,但有时候,过于追求简化也是很困难的。你希望丢掉所有不必要的东西做到极简化,但还要考虑是否有时间去做。

我们讨论过重写的问题,这里谈谈重复代码的问题。这个案例与《英雄联盟》相关,具体说是邀请好友功能,我们加入了验证环节,比如你是否拥有这款游戏,你邀请的人是否玩过《英雄联盟》,基本上,这个代码就是从之前平台复制粘贴的,当我加入的时候,发现很多验证失控现象,这并不是好现象,因为它带来了bug,而且不利于追踪。

随后我们发现,这个代码加入了太多的东西,比如玩家背包,这款游戏共有10个玩家,假设每个人都有50个背包位置,意味着这个代码需要验证很多的东西,才能得到三行代码就能得到的结果。最后,我们将它简化为,检查玩家背包、找到某个东西,然后继续。

这里的目标是,不要自我重复,这样在做出改变的时候就更容易,当你做规模化的时候,也可以带来更多帮助,做起来很困难,但是很值得。

以上就是今天分享的全部内容。

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

关注微信