云上游戏:玩家直连游戏服的云原生化实现

容器服务

picture.image

本文为『云上游戏』实操系列第二篇,将介绍玩家直连游戏服背后的架构设计和云原生方案,前一篇:云上游戏:会话类游戏该如何进行云原生部署?

来源 | 火山引擎云原生团队

一、引言

在会话类的游戏场景下,每次对局都要新开一个房间。玩家通常需要连接到指定的房间游戏服进行游戏,一个游戏服即为一个 Pod。在 Kubernetes 中,Pod 大都是通过 service 暴露的,用户通过 service 访问时,会被负载均衡到某一个副本,但是在开房间类的游戏中用户的请求不能被负载均衡到随机 Pod,而是需要访问一个指定的 Pod。因此在某些游戏场景下,Pod 被创建时需要分配一个固定的访问地址,然后暴露给玩家进行访问。

针对这种场景,本文将介绍在火山引擎容器服务 VKE 中,使用火山引擎弹性容器实例 VCI 运行游戏服,通过 OKG/CLB/EIP/APIG 为游戏服分配指定的访问地址并且传递访问地址给游戏服,实现玩家直连游戏服,更好地服务游戏云原生化。

二、访问游戏指定服场景分析

在游戏场景中,玩家对游戏服的访问有不同要求。对于登录服务、商城服务等公共服务,玩家进入任何一个副本都可以。如下图所示,这类服务在容器化之后,可以通过 LB 进行负载均衡,用户登陆同类服务的任何一个副本都行。这种用法与 Kubernetes 中 service 一致,使用 Kubernetes 原生方案即可。

picture.image

但是对于房间类的游戏服,玩家经过匹配或者自己开房间后,就需要登陆到指定的游戏服中,而不能随机登陆到其他同类游戏服。这要求玩家到游戏服的访问中不能经过负载均衡,需要直连游戏服。如下图所示,为了满足玩家直连游戏服的需求,当游戏服创建出来后就需要给其分配一个唯一访问地址,供外部玩家访问。

picture.image

除了在游戏服创建出来时分配特定的游戏服外,还需要将该游戏服的访问地址暴露给玩家,供玩家登陆。这就需要游戏服能感知到自身的访问地址,并且上报给其他服务,这也是游戏服云原生化时需要解决的。

三、火山引擎云原生解决方案

云原生技术栈

本文将以火山引擎为例,演示如何通过云原生的方式实现玩家直连游戏服,需要用到以下云产品:

开源项目:

3.2 四层直连

3 .2.1 基于 CLB 的四层直连

解决直连游戏服的核心问题为如何给每个游戏服副本都提供特定的访问地址,并将该地址暴露出去。游戏服云原生化后,一个游戏服即为一个 Pod。在 Kubernetes 中,为 Pod 提供外部访问地址一般通过 LoadBalancer(云负载均衡器)实现,但是常见的 LB 使用方式都为一个 LB 的后端会有多个 Pod,请求会负载均衡到后端所有的 Pod 上面,而不是指定的某个 Pod 上。

picture.image

在直连游戏服场景下,可以让后端的 Pod 仍然共用一个 LB,但是每个 Pod 都使用不同的端口。这样玩家就可以通过访问 LB 的不同端口登陆到指定的游戏服中,这种 LB 的使用方式才是游戏服所需要的。

picture.image

OKG 是专用于游戏云原生化的组件,为游戏云原生化中遇到的问题大都提供了解决方案。OKG 使用 GameServerSet 来管理游戏服,GameServerSet 类似于 Kubernetes 原生负载中的 statefulset,可以管理多个 GameServer 副本,每个 GameServer 副本对应一个 Pod。为了解决游戏服直连的问题,OKG 提供了Volcengine-CLB 网络插件,可以支持 GameServerSet 的多个副本复用同一个 CLB,但是会被分配不同的端口。

如下图所示,在创建 GameServerSet 时指定一个 CLB,然后 GameServerSet 就会为每个 GameServer 的副本分配一个 CLB 的端口。GameServerSet 会保证每个 GameServer 副本的端口不冲突,并且即使 GameServer 重建后其所分配的 CLB 端口仍然不变,保证访问的一致性。每个 GameServer 即对应一个 Pod,并会为每个 Pod 都创建一个 CLB 类型的 SVC,保证玩家的访问只会到指定的游戏服中。此外,即使游戏服被销毁重建,其访问地址仍然保持不变。

picture.image

通过上述方案,我们就可以为游戏服对应 Pod 分配特定访问地址。除此之外,还需要能让游戏服感知到自身的访问地址,以便上报给其他服务,提供为玩家访问。上述方案中,GameServerSet 为 Pod 分配完访问地址后,其访问地址会被写到对应 Pod 的 anno 上。如下所示,game.kruise.io/network-status 中记录了 Pod 的访问地址和端口,其中 externalAddresses 为外部访问地址和端口。该信息可以挂载到 Pod 内部的指定文件中,游戏服读取该文件即可获取自身的访问地址。


          
apiVersion: v1
          
kind: Pod
          
metadata:
          
  annotations:
          
    game.kruise.io/network-status: '{"internalAddresses":[{"ip":"192.168.0.64","ports":[{"name":"80","protocol":"TCP","port":80}]}],"externalAddresses":[{"ip":"101.xxx.xxx.xxx","ports":[{"name":"80","protocol":"TCP","port":677}]}],"currentNetworkState":"Ready","createTime":null,"lastTransitionTime":null}'
          
    game.kruise.io/network-type: Volcengine-CLB
          
    ···
      

3.2.2 基于 EIP 的四层直连

上面的方案是借助 OKG 组件通过 CLB 暴露游戏服,不同的游戏服分配不同的 CLB 端口。此外,我们还可以通过为 Pod 绑定 EIP 的方式,实现直连游戏服。火山引擎容器服务 VKE 提供了 vpc-cni-controlplane 组件,可以在 Pod 创建时,为 Pod 创建并绑定 EIP。如下图所示,每个游戏服都会有一个专属的 EIP,通过该 EIP 可以访问到该游戏服。

picture.image

用户只需在 deployment 中添加如下 annotation,即可说明想要分配的 EIP 参数,vpc-cni-controlplane 组件会在 Pod 创建时根据 Pod 中的 anno 设置,自动创建 EIP 并绑定到 Pod 上。


          
vke.volcengine.com/primary-eip-allocate: '{"type": "Elastic"}'
          
vke.volcengine.com/primary-eip-attributes: '{ "name": "eip-demo", "description":
          
          "demo for pods eip", "isp": "BGP", "billingType": 3, "projectName": "default",
          
          "bandwidth": 200 }'
      

vpc-cni-controlplane 实现 Pod 绑定 EIP 的方式如下:

  • Pod 在创建时,anno 中会带上需要的 EIP 规格信息;
  • vpc-cni-controlplane 中的 EIP Controller 在 watch 到 Pod 的创建后,调用 EIP 的接口创建 EIP,并且为 Pod 绑定 EIP;
  • 将 EIP 的信息回写到 Pod 上。

picture.image

绑定成功后,会将 EIP 信息写到 Pod 的 annotation 上,annotation 的 key 为vke.volcengine.com/allocated-eips。再将该信息挂载到 Pod 内部,游戏服即可感知到自身的访问地址。


        
            

           vke.volcengine.com/allocated-eips: '[{"EipId":"eip-13fx60maj7jls3n6nu52f2znx","EipAddress":"1xx.xxx.xx.xx","EniId":"eni-13fdawbnw97gg3n6nu3y2dnfm","EniIp":"1xx.xxx.x.xx"}]'
        
      

3.3 七层直连

对于 Web 类游戏而言,需要使用 7 层负载均衡作为网络的入口。在这种场景下,我们可以使用火山引擎 API 网关 APIG(API Gateway)来解决游戏服务特殊的网络诉求,实现直连到某个游戏服。

API 网关是基于云原生的、高扩展、高可用的云上网关托管服务。在传统流量网关的基础上,集成丰富的服务发现和服务治理能力,打通微服务架构的内外部网络,快速实现各服务之间、服务与客户端之间的安全通信。

picture.image

API 网关通过 api gateway controller 组件读取 Pod name 信息和 Pod ip 信息,并且将该映射关系并写入到网关的后端列表中。在用户请求游戏服时,只需再添加 x-target-pod-name header,header 的值为 Pod 名称。API 网关就会根据记录的 Pod 信息映射表,将该请求路由到指定的 Pod 中。如果在 header 中不指定任何 Pod 信息,则会随机负载到任何一个 Pod 上。通过该方式,用户可以非常方便地访问指定的 Pod。

另外,还可以支持指定范围的负载均衡,若一组 Pod 具有相同的 label,则可以在请求的 header 中添加期望的 label,选择将请求打到这一组 Pod 上。APIG 会将请求随机负载到该组内的任何一个 Pod 上。

picture.image

四、结语

以上讨论了游戏服云原生改造后,对游戏服直连问题的解决方案, 并且针对四层和七层场景都提供了相应的解决方案, 能较好的解决游戏服云原生改造的网络问题,并且对游戏服都无侵入,用户也无需更改游戏服代码。 上述用到的组件都已经集成于 VKE 的组件/应用市场中,可以一键安装使用。

随着越来越多游戏公司开始通过云原生提升用云效率、用云体验,火山引擎云基础团队也积极与游戏行业合作, 围绕平台、用户、资源等多维度探索游戏企业敏捷创新、降本增效的数字化升级之路,并积累了丰富经验。 欢迎感兴趣的用户咨询:

picture.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

picture.image

picture.image

picture.image

0
0
0
0
关于作者
相关资源
KubeZoo: 轻量级 Kubernetes 多租户方案探索与实践
伴随云原生技术的发展,多个租户共享 Kubernetes 集群资源的业务需求应运而生,社区现有方案各有侧重,但是在海量小租户的场景下仍然存在改进空间。本次分享对现有多租户方案进行了总结和对比,然后提出一种基于协议转换的轻量级 Kubernetes 网关服务:KubeZoo,该方案能够显著降低多租户控制面带来的资源和运维成本,同时提供安全可靠的租户隔离性。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论