国家新闻出版署8月30日下发切实防止未成年人沉迷网络游戏的通知,要求从今天(9月1日)起,所有网络游戏企业仅可在周五、周六、周日和法定节假日每日20时至21时向未成年人提供1小时服务,其他时间均不得以任何形式向未成年人提供网络游戏服务。通知发布后,各大游戏厂商火速回应,纷纷表示将从严落实未成年人网游防沉迷新规。
目前整个游戏行业也只能遵照新规来做,今天我给大家带来游戏后台的设计简要分析,这里我把他分为两类:
- 匹配竞技类游戏(如王者荣耀,CFM类游戏等,其核心难点在于极低的时延要求)
- 虚拟大世界类游戏(如天涯明月刀,天谕手游等,其核心难点在于无缝世界切换,大规模玩家集结时数据同步问题)
除此之外,其他类型游戏在游戏后台设计方面,其实无需考虑过多,如莉莉丝的AFK(剑与远征),bilibili的坎特博雷公主与骑士唤醒冠军之剑的奇幻冒险这一类卡牌游戏,既不需要对网络时延有极高的要求(100ms的延迟或者200ms延迟其实对玩家感知影响并不大),也不会有大量数据同步需求导致网络流量暴增,服务器处理卡顿的问题。
所以除了匹配竞技类游戏与虚拟大世界类游戏,我们可以把其他游戏后台设计归类到普通互联网后台设计即可,这一类游戏后台设计采用通用解决方案,即使后台完全做成无状态化,玩家数量增加的时候同比例扩缩容时便可以满足玩家需求,在此便不再讨论。
本文主要讨论匹配竞技类游戏的大型游戏后台实践的一些浅薄看法,后面有空再另外开一篇讨论虚拟大世界类游戏后台设计的文章。
其实从另外一个角度来看,除了虚拟大世界类游戏后台之外,其他类型游戏后台设计都可以沿用借鉴匹配竞技类后台的设计。不过可能对于一部分轻度游戏来说可能过于厚重了。
一、何谓匹配竞技类游戏?
这里我们要下一个定义:匹配竞技类游戏,便是核心单局玩法在于玩家经过匹配组队后,进行强PVP对战,要求低网络延迟,实时同步。一般以MOBA类游戏,FPS游戏,ACT游戏为主。再具体一点说便是王者荣耀,CFM,火影忍者等此类游戏为主。
二、匹配竞技类游戏后台设计的难点在哪里?
三句话概括,低时延,低时延,还是低时延!
三、匹配竞技类游戏后台设计思路
围绕我们的主题,我们这里面主要需要解决两个大问题:
- 大DAU(我认为的大DAU是指百万级别(含)及以上DAU)
- 单局交互低时延
从一个游戏整体来看,游戏内容纯PVP是很少的,即使是王者荣耀这种类型的游戏,也是要加入一定PVE内容和众多的周边系统如商城,邮件,好友等。
所以设计分两块,其一是周边系统后台设计,其二是核心战斗单局后台设计。
周边系统后台设计其实没有低时延的要求,如领一封邮件,100ms领到与200ms领到玩家体验区别并不大,玩家对这块的时延要求并不高。仅在于需要承担起大量用户的请求。那这个其实关键在于服务拆分与服务集群分。
核心战斗单局后台设计要求就是不仅要有大量用户请求交互还要求极低的时延。车枪球拳类游戏,除了赛车类游戏对时延要求更高采用解决方案通常为状态同步或者说属性同步,而对于枪球拳类游戏基本使用的解决方案是帧同步。我们后面也以帧同步为基础讲解一下核心战斗单局后台的设计思路。
游戏后台分层设计
基本游戏后台设计包括互联网游戏后台设计都可以分成三层:
编辑
- 接入层:主要负责与客户端建立连接,检测客户端存活情况,包括排队保护,通用的鉴权功能也可以在这一层做了。
- 逻辑层:这里主要游戏的各种业务逻辑的实现,如领取邮件,添加好友,参加任务等等。
- 存储层:顾名思义,便是将玩家数据进行落库存储。
这里有一点需要注意的是,从软件工程实践的角度来看,像接入层与存储层的代码应当是极少改动的,同时这两块的功能也应当是非常稳定的。所以在项目开发中,应当把接入层,逻辑层,存储层彻底分开,在代码设计上不应有任何耦合。这三层的交互底层全部通过消息队列来实现。代码层次上三层不应该有任何互相引用的地方,除了消息队列处理库代码是共享的除外。
匹配竞技类游戏后台概要设计
我们先放上一张大致的架构设计图,通常来说,有两种类型:
第一:有中心proxy的架构设计思路
编辑
这里面需要注意的是周边系统的各个svr进程间的通信都是通过proxy来转发,因为建立proxy建立非常多,一般来说proxy进程的部署机器选择为大内存机型机器。从经验来看,很多游戏设计模式基本都是沿着proxy转发的方式来进行设计的。
第二:无中心proxy的架构设计思路
编辑
无中心proxy的架构设计思路,其实类似于我们经常说的service mesh设计,sidecar是接用了service mesh那边的概念,表达便是各个server启动成功后,向NameSever注册,然后与所有server直接直连,消息转发不需要经过中间的跳转。(为避免图片过于复杂,sidecar之间本来是全连,现在只通过一个sidecar的全连来表达)
本文主要从第一种有中心proxy的后台讲开去。
匹配竞技类周边系统后台设计概述
沿着通用的三层分层设计,我们可以逐步展开我们的游戏后台周边系统设计,主要是在于支持大DAU, 同时要从设计上去杜绝服务器开服炸服的情况。
从业务角度出发,游戏通常有分区分服的业务需求如王者荣耀,QQ飞车手游等,当然也有全游戏单区单服的如一起来捉妖。从游戏后台发展的演变过程来看,以往的游戏针对分区分服的设计主要在于物理进程上的分区分服,画个图示意一下:
编辑
一个小区对应的一个gamesvr
这种设计在以前比较流行,但是这种方式是实现简单,但是我们可以清楚的是,既然有分区分服,就会滚服的需求。这种设计有两个缺点:
其一:从满足需求的角度出发,这种设计对于滚服需求来说,人工的操作太多了,对研发人员不友好。(一旦发新版本,有滚服需求,研发人员都要加班加点搞)
其二:从服务器成本出发,单个gamesvr对应一个小区,在小区活跃人数较少的时候,服务器资源利用率低,服务器成本很难降下来,意味着大家的年终奖又少了。
所以通过逐年的演变,现在比较通用的设计是:服务器设计上为全区全服设计,逻辑上是分区分服的设计。这种怎么理解呢?
所谓逻辑上分区分服,设计上全区全服的意思便是,每一个gamesvr上登陆的玩家可以是任意小区的,也就是每一个gamesvr都是等价的,玩家登陆1小区,可以连接到gamesvr1, 也可以连接到gamesvr2。然后对于那些需要以小区区分的需求,大多抽象到另外一个server上去实现。举个例子,小区的聊天服,为了消息转发方便,这里一般整个小区的聊天服会集中一个chatsvr, 所有1小区玩家的聊天的信息都会通过proxy 经过hash走到同一个chatsvr(图中颜色仅用来表达消息发送链路)
编辑
大家这里可能会说当1小区到10小区活跃数很少的时候,chatsvr进程也是浪费资源。确实如此。但是chatsvr的浪费相比gamesvr来说会少很多。因为gamesvr通常来说逻辑复杂度相对chatsvr高非常非常多,而且又有大量的玩家数据在上面,业务复杂度极高,通常来说一个gamesvr可以支撑1w玩家的同时在线,已是非常不易的事情。
匹配竞技类战斗单局后台设计概述
低时延,在帧同步的战斗单局中,主要是用过优化网络协议,如使用可靠UDP,前向冗余算法,将每个网络包的大小降低到Internet标准MTU值为576字节以下防止交互机或者路由器将包分片等等,主要目的都是为了提高收发包成功率。
匹配竞技类采用帧同步功能,relaysvr进程主要负责最基本的帧同步功能,所有和业务相关的如完成任务,捡起掉落等业务逻辑则放在pvpsvr进程去实现会更好。pvpsvr主要负责一个relaysvr负载监控,新开一个单局时选择一个合适relaysvr地址返回给客户端。
作为匹配竞技类游戏来说,pvp单局是一个非常耗服务器资源的地方,所以会有很多团队在这方面去做很多工夫,例如结合k8s,希望可以做到自动缩扩容以提高资源利用率等等。
编辑
四、游戏后台开发质量保障通用手段
规范保障
站在个人的角度来看,任何软件工程实践项目之初务必要先立规范,这里的规范有很多个。如:
- 代码规范。代码规范太重要了,诚如有人说过,人人都可以写出机器可以理解的代码,但是不是人人都可以写出别人可以理解的代码。这是多人协作项目里面非常基础也是非常重要的一点。一般采用指定代码规范,最好与开源界保持一致,然后使用如clang-format类与lint类工具去保证代码规范会使整个项目代码风格逐步收敛(还有很重要的一点:便是注释规范,规范的注释跟正确的代码一样的重要)。
- 设计规范。这里主要是指业务研发过程中各种设计的规范。最好是团队内能有统一的设计模板,在设计一个系统如跨服战斗玩法时,按照模板来梳理整个设计流程。一般覆盖:需求说明,协议设计,存储设计,监控设计,链路设计,告警设计,排期规划等等。基本上各个团队根据各自的特点制作即可。
- 协作规范。这里主要是针对不同版本控制工具(svn, git, perforce)衍生而来的团队协作模式。代码协作方面一边都是采用git,团队内要规划好是使用git工作流,github工作流,gitlab工作流等等(Git 工作流程 - 阮一峰的网络日志)。通常来说大型多人协作工作流还是推荐gitlab工作流。还有一个问题便是git对于美术,策划同学使用是很高学习成本的,一般都不太愿意使用。这一点需要做好团队根据自身特点做好选择。而且git对于美术同学来说确实使用并没有那么方便,很多都是沿用svn或者改用perforce。
- 少滥用高级特性。这一点主要针对业务代码而言,公共代码库为了支持代码的可扩展性,使用高级特性是可以理解并需要支持的。但是在业务代码里面使用实在是不适合。首先高级特性就意味团队内有一部分同学大概率不知道,他们要去看代码的时候就会有很大成本,理解成本高了改动成本也高了,对于游戏这种需求变更频繁的业务来说,在业务代码里面使用高级特性的,大概率是坑。
测试保障
- 单元测试。主要用来测试公共代码库中一些函数
- 场景测试。或说协议测试,单元测试无法做到覆盖有很多类对象的函数,很多mock非常消耗人力去实现。如使用道具是一个典型的场景,这个场景测试覆盖的协议有:登陆,创角,道具使用等一系列协议,可以有效地覆盖到很多业务代码。
- 边界测试。这里主要为了验证软件各种边界是否处理正确。
单元测试可以在代码合入前时运行验证(git工作流)。场景测试与边界测试通过稳定的流水线来定时跑,有问题则定时抛出问题,通过邮件,微信等通知研发人员去关注。以此及早发现潜在问题,提高软件质量。
可观测性保障
- 日志。这是最为常见的业务调试手段,日志打印应尽可能包含尽量多的上下文信息,不要嫌弃日志打印代码过长,这对于线上业务来说那可是追溯问题根源的信息。打好日志也是挺有讲究的,但这种工夫,只能依赖研发人员自己重视,或者review代码人员指出。
- 监控。这里主要包含各种业务指标的统计如全网实时登陆人数统计图,全网实时使用A道具的统计图。与各种运维指标(与机器CPU,内存,IO相关统计指标)。告警,这一块是非常非常重要的,告警方式诸如微信通知,电话通知等等,一边告警要慎用,避免无效告警,研发人员麻木,导致重大问题没有得到及时处理。告警指标,例如游戏内账号仅能使用一次道具被使用两次需要告警,发生core等重大业务错误都需要及时告警。
- 链路跟踪。通常来说错误链路上报与采样上报可以帮助捋清很多调用链方面的问题。在现在微服务设计理念越来越流行的情况。链路跟踪确实是一块很值得建设的能力。这里可以看看这一篇文章天机阁——全链路跟踪系统设计与实现-InfoQ
五、游戏出版本的问题
这一块其实只是个人单纯想说说,因为出版本是造成游戏研发人员大量加班的重要原因之一,为了提高研发人员,这里不止说开发人员还有美术,策划与测试的工作幸福感。提高游戏出包,出版本的成功率是一个极具价值的研究命题。
多少时间消耗在反复出包上。游戏出版本主要痛点在于客户端打包需要很长时间,一般短则半小时,长则一个多小时。一旦一个包有阻断性bug,那么再打一个包,大家就都得在那等一个小时。这一个小时的等待是一个极其令人痛苦的事情。
所以站在一个PM角度来看,每天最害怕的就是:客户端包构建失败、服务器起不来、阻断性BUG等等。
那如何解决这个问题?
bug是不可能没有的,假设每个人每天出错考虑仅为1%,那么50人协作项目,假设50人今天同时往一个仓库里面提交代码,那么出包的成功率为:(1 - 1%)^50 = 60%,如果是100人协作项目那么成功率仅有36%, 意味着100人协作项目最少要出2个到3个包才有可能成功。如果是150人呢,这里还只是考虑了人的问题,机器呢,CDN呢,第三方支撑平台出问题呢,所以说出包失败基本就是板上钉钉的事情。
所以单纯提高代码质量的路子走不通,这里要拆分开来,不要让大家都往一个仓库去提交代码,特别是客户端和美术,这里一定要拆成多个仓库,出版本时通过tag版本来对接这样才有可能提高出包成功率。
当然这里涉及的更多是版本管理工具与项目管理的知识,这一块也仅是本人日常的一些简单思考。持续思考中与对比不同项目的解决方案中,后面也许可以再写一篇专门分析游戏出版本与出包的思考。
六、游戏后台成本核算分析
这一块也是一个很大的议题,一个好的后台设计人员不能不看到全面的成本核算问题,服务器成本下来了,意味着游戏盈利上升,大家的年终奖增加又有戏了。这一块目前还在分析中,后面有时间再写一篇分析成本的文章。
以上便是个人对大型游戏后台软件工程实践的一些浅薄见解,欢迎各位一起讨论。