字节跳动云原生

云上游戏:会话类游戏该如何进行云原生部署?

Image

相较于普通无状态类在线业务,游戏业务由于其自身的有状态特性,在云原生改造过程中会遇到一些挑战。

来源 | 云基础 - 解决方案
Image

互联网游戏行业作为最早开始尝试云计算产品与服务的行业之一,多数客户已经充分了解公有云在资源使用效率、资源上线速度、技术领先性以及降低资本性支出等方面的独特优势。在过去三年中,除个别周期外,游戏云用量基本维持了稳步增长的态势,在新游项目中使用更高比例的公有云产品与服务正在成为行业共识。

——IDC:2023 年中国游戏云市场

随着云原生技术的不断发展,越来越多游戏厂商纷纷选择使用容器化的形式来部署在线游戏服务,并使用 DevOps 流程来提升开发迭代和部署的效率。结合游戏开发运营场景,目前云原生技术可以为游戏业务带来以下几个方面的提升:

弹性伸缩:游戏业务具有非常明显的流量尖刺,一款突然爆火的在线游戏对计算资源的需求会在短时间内成倍提升,这对于使用传统部署手段以及自建 IDC 机房的游戏运维团队而言是个巨大的挑战。在这类场景下,使用云厂商近乎“无限”的云资源,并结合 Kubernetes、容器化技术所带来的弹性优势来应对突发流量已成为现代运维团队的首选。

快速部署和迭代:容器化技术结合 DevOps 自动化流程带来的高效部署能力,能够极大提升游戏服务的开发迭代效率。面向 Kubernetes 的持续交付流程可以做到自动化、标准化,帮助游戏公司在提升部署效率的同时,降低人为错误率。

高可用性和容错性:Kubernetes 作为云原生技术的基础设施,天然为游戏服务提供了故障自愈的能力,同时云厂商也为计算资源提供了 SLA 作为双重保障。

成本效益:云原生技术能够显著提升游戏服务的资源利用率,在业务高峰期迅速补充资源保障游戏平稳运行,并在业务低谷时及时回收资源,做到真正的按需付费,节约云成本。

然而,相较于普通的无状态类在线业务,游戏业务由于其自身的有状态特性,在云原生改造过程中会遇到不少难题。在这篇文章中,我们将探讨会话类游戏业务的特性,以及火山引擎云基础团队提供的对应解决方案。
会话类游戏业务架构分析
会话类游戏架构

会话类游戏是指在有限的时间内,将玩家汇聚到特定游戏场景下的游戏类型,也常被称为“开房间”类游戏。MOBA、FPS 类的游戏往往会使用会话类游戏的架构,这类游戏的核心玩法是将若干玩家匹配到同一个战场中去,对局会在一段时间的战斗之后结束,之后所有玩家就会断开“会话”连接。除了短时间的会话对局之外,这类游戏往往具有大厅服的游戏服务,用于支撑分区分服的游戏架构。相比微信小游戏这样的 Web 类架构,会话类游戏的架构更加复杂,在云原生改造及部署的过程中需要技术团队做更多处理。

以下是一个利用火山引擎云服务部署的会话类游戏的架构图:

Image

从玩家与游戏服务端的交互视角来看,玩家在玩这样一款游戏时会经历以下过程:

  • 本地开启游戏客户端,输入用户名与密码,与登录服务交互完成登录的操作;

  • 选择自己想要登录的游戏大厅,游戏客户端会主动与大厅服务的网络地址进行直连,玩家获取到自己位于这个大厅的游戏角色;

  • 玩家在大厅中发起对局匹配的请求,匹配服务收到请求后会开始在同个大厅内的玩家之间开始匹配,最终圈定一批水平相近的玩家。同时匹配服务会查询当前是否有空闲状态的战斗服,并创建出专属这批玩家的游戏房间,将这个战斗服的直连地址返回给这批玩家的客户端。如果匹配服务发现空闲的战斗服数量不足,则动态的创建出新的战斗服备用;

  • 玩家的客户端获取到房间地址后,都会建立会话连接。所有玩家就绪之后就会开启一场几十分钟的游戏对局。一方胜利之后,战斗服会校验积分结果,并将数据写入数据库。玩家断开连接之后,房间销毁。

大多数有玩家对抗(PVP)属性或者副本人机对抗(PVE)属性的游戏架构,都与上述游戏架构有相似之处。

会话类游戏云原生化的挑战

基于上文介绍的会话类游戏架构的特殊性,结合火山引擎在支持游戏厂商开展业务云原生改造的实践,在云原生环境中,部署会话类游戏服务通常会面临以下几个挑战:

  • 入口网络模式:会话类的游戏中,大厅服和战斗服(即房间)的网络要求是比较特殊的。每一个 Pod 实例都会暴露一个全局唯一的入口地址给玩家,这是一种客户端直连 Pod 的方式,和传统 Kubernetes 模式下基于负载均衡暴露服务的方式是相悖的;

  • 开/合服机制:在分区分服的架构中,需要考虑好大厅服如何部署更方便。每个大厅可以对应到游戏玩法中 “服” 的概念,每当游戏开新服的时候,实际上就是将相同的一套大厅服业务,稍微改动一些配置后部署一套。抽象思考一下,其实就是同一套模版,面向不同的环境,通过差异化配置的渲染,生成出很类似的一系列 Pod。我们可以利用产品化的能力来降低开服过程中的重复工作量,提升效率。分区分服架构下的游戏还有一个比较特殊的场景,就是要进行合服操作,这也需要我们给出云原生场景下的合理方案;

  • 弹性机制:会话类游戏中,既有公共服务、大厅服这类长稳运行的在线业务,也有需要根据玩家对局实时生成的弹性战斗服。战斗服的计算资源用量,会受到玩家流量的影响。从游戏设计的视角来看,战斗服的生成与销毁,最好可以由玩家对局来驱动,做到弹性与按需。
会话类游戏的云原生部署
入口网络解决方案

对于会话类游戏,如何能够让玩家直连大厅服、战斗服这类特殊的游戏服务,是云原生改造过程中需要重点关注的问题。

传统的 Kubernetes 会借助负载均衡将流量均匀的分散到所有业务 Pod 上去,并不会为某个指定的 Pod 做流量转发,这显然不符合游戏业务的诉求。我们可以转换思路,仅使用负载均衡的转发能力,将流量直接转发到指定的游戏服务 Pod 上去。这里有两点需要关注:

  • 针对不同类型的负载均衡,应该如何提供一个固定且唯一的对外服务地址;

  • 每个大厅服或者战斗服 Pod,如何提供独立的 Label 供负载均衡 Service 选择。

◇四层 TCP 实现方式

在游戏业务场景中,客户端与服务端之间使用 TCP/UDP 协议进行交互是非常常见的。相对于应用层协议而言,四层的网络通信协议往往更高效,这对于延迟敏感的游戏业务非常重要。在这种情况下,我们可以通过四层负载均衡器的不同端口,来提供固定且唯一的对外服务地址。

为了给每个游戏服务 Pod 提供独立的 Label ,我们可以使用单独的控制器来管理每个 Pod 。

Image

在这个转发链条中,每有一个大厅服,就需要生成相对应的 Deployment 与 Service 资源,手动编写这些 YAML 配置是一件繁复的工作,我们会在后文中介绍基于 OAM 编排游戏服务的方法:可以将大厅服所需的资源抽象称为模版,简单配置后即可快速复制,极大提升效率的同时,降低人为错误的概率。

◇ 七层 HTTP 实现方式

对于使用了 HTTP/WebSocket 这样的七层协议的游戏业务,我们建议使用子路径对不同的游戏服务 Pod 进行代理。与上文中使用四层负载均衡不同的是,七层负载均衡一定要支持路径重写的能力,将不同的子路径都重写到 Pod 本身提供服务的路径上去。

Image

◇ Pod 绑定 EIP

为每一个 Pod 绑定 EIP 是最直接、最简单的解决方案,这是我们提供给弹性生成战斗服的首选项。这个能力往往是需要与云厂商提供的 CNI 方案相配合方可使用,如火山引擎容器服务 VKE 所提供的 VPC-CNI 网络模式。通过配置,EIP 可以与战斗服的 Pod 同步生成与销毁。

对于战斗服的入口网络,往往伴随着一个特殊的诉求,战斗服在启动时可以获悉本 Pod 的入口网络地址,并汇报给上层的匹配服务。Pod 绑定 EIP 这个方案可以很好地解决这个问题,EIP 一旦分配给游戏服务 Pod,系统就会将相关的网络信息写入到 Pod 的 annotations 中去,通过配置,我们可以将 annotations 中的内容写入到容器环境中的一个文件中,游戏服务进程通过读取这个文件,就可以得知当前 Pod 被分配的 EIP 地址。

OAM 编排游戏服务

我们推荐使用 OAM 思想,以应用视角来部署运维游戏业务。开发人员可以自由定义应用程序组件。游戏运维人员负责创建这些组件的实例并为它们分配指定的配置信息。火山引擎提供了完整的 OAM 产品化能力,助力游戏业务运维人员快速编排出符合游戏业务诉求的应用模版,并基于差异化配置完成开/合服操作。所有的操作都是在白屏化的界面中完成的。

Image

游戏运维人员基于 OAM 模版创建实例时,可以根据填入预置的变量配置,来发布不同的环境。环境的区分比较灵活,根据使用模版的不同,既可以是服务不同地域玩家的各种大厅服,也可以是包含了全部游戏服务的测试服、审核服等。通过简单的配置,运维人员可以在几分钟之内完成配置,并将游戏服务发布到对应的环境中。

◇ 大厅服开服

大厅服的开服是非常适合使用 OAM 编排能力的场景。前文说到,大厅服的网络入口地址需要能够被客户端直连,例如在四层 TCP 的场景中,需要同时生成 Deployment (或者其他任意你需要的工作负载控制器)与 Service 来完成大厅服与四层负载均衡不同端口之间的映射关系。遵循以下几点,就可以设计出适合大厅服的 OAM 模版,并快速发布出不同的环境:

  • 环境被创建时,会要求填写全局唯一的环境标识字符串,模版中可以利用预置的变量来引用这个值;

  • 模版中可以自定义一些变量,在创建环境时引用。在分区分服的游戏架构中,不同的大厅服之间只有微小的配置差异,比如大厅服的 Server ID 、负载均衡对外的端口等;

  • 定义 Deployment,并使用环境标识来定义大厅服 Pod 的 Label。使用环境变量的形式,将 Server ID 信息注入到 Pod 环境中去;

  • 定义 Loadbalancer 类型的 Service ,使用 selector 匹配到大厅服 Pod 的 Label,实现与指定大厅服的绑定关系。同时通过自定义的变量来定义负载均衡对外的端口。

◇ 大厅服合服

一款游戏很难做到常年火爆,随着玩家的流失,运营人员不得不面对的一个问题就是将玩家数量较少的大厅服合并到其他大厅服中去。

一般的合服操作(将 A 服合并到 B 服)会包含几个步骤:

  • 整合 A、B 服的数据库,将 A 服的玩家数据插入到 B 服数据库中去;

  • 调整 A 服的网络流量入口,将其指向 B 服服务器。这样可以不用对客户端中的服务器列表做出改动;

  • 确认原 A 服玩家已经连入 B 服,且游戏逻辑正常后,关停 A 服务器,释放资源。

在云原生场景下,OAM 编排可以非常轻松的适配这种合服的操作。

Image

在 OAM 编排过程中,我们只需要将 service 资源中指向 Pod 的 selector 作为一个变量提取出来,在合服时重新定义,从本大厅服改成目标大厅服 Pod 即可。后续的操作是将被合并的大厅服 Deployment 中副本数量置零。

弹性容器实例与战斗服

我们推荐游戏服务的研发人员在匹配服务中设计逻辑,直接对接 K8s Apiserver 接口,在有玩家匹配申请时调度出独立的房间服务供玩家游玩。在云资源一侧,火山引擎能够提供按需付费的弹性容器实例供游戏服务调度使用,这是一种 Serverless 化的容器使用形式,无需计算节点即可在集群中生成 Pod。我们推荐使用常态 ECS 计算节点与弹性容器实例 VCI 混合使用。在保证有一定量的常态战斗服 Pod 在线的前提下,能够动态的生成 “近乎无限” 的弹性战斗服 Pod。

Image
游戏服务具有非常明显的潮汐特性,业务高峰集中在工作日的午休时间,以及晚上下班放学之后。在常规的部署形态下,运维人员需要根据经验,按照峰值来准备服务器,并在节假日来临之前,临时部署一批额外的服务器来迎接流量。使用弹性容器实例的方式部署,则可以让计算资源始终与业务需求趋近,自动化弹出按需付费的资源,同时降低人力成本与计算资源成本。
结语

在充满变化与机遇的当下,为了更好地匹配玩家偏好,适应游戏产业精品化、全球化的大趋势,越来越多游戏公司开始围绕平台、用户、资源等多维度进行探索,探索敏捷创新、降本增效的数字化升级之路。而云计算凭借其弹性、成本优势以及快速的技术迭代,天然适配游戏产业对创新与融合的需求。

火山引擎云基础团队通过提供强大的底层算力、高兼容性以及低延迟传输,致力于为客户提供全方位的云上产品解决方案和最佳上云实践。未来,我们将持续为各行业领域的企业客户提供优质的产品服务,帮助各多企业客户突破瓶颈,实现自由计算、自由增长。

Image

相关链接
[1] 火山引擎: www.volcengine.com
[2] VKE:www.volcengine.com/product/vke
[3] VCI:www.volcengine.com/docs/6460/76908
[4] ECS:www.volcengine.com/product/ecs
Image

Image

Image