网易伏羲云原生游戏中间件平台实践


【编者的话】网易伏羲成立于2017年,是国内专业从事游戏与泛娱乐AI研究和应用的顶尖机构。为了更好的为游戏提供中间件服务支持,伏羲云计算团队构建了伏羲云原生游戏中间件平台。本文主要介绍伏羲云原生游戏中间件平台的实践过程。

背景与场景

伏羲私有云为游戏以及AI研究应用提供完善、可靠的计算能力。游戏作为网易的核心业务,如何更好的为游戏服务是平台的重点。

游戏是网易的核心业务。在游戏项目中,从游戏的开发、测试、到上线各个阶段都具有各种中间件的需求。在此背景下,对我们如何为游戏提供高效、可靠的中间件服务提出巨大的挑战。

传统的方式是通过运维人员手动搭建维护,而这种方式主要存在下面问题:
  • 环境依赖:服务可能会因为基础环境的变化导致异常情况。
  • 缺少标准化:各个游戏项目对中间件的使用方式存在差异。
  • 缺少平台统一动态管理:缺少统一平台进行创建、删除等自主运维能力。
  • 服务可靠性低:服务不可用等状态难以及时发现,以及人工修复效率比较低。


为了解决这些问题,伏羲云计算团队构建了云原生游戏中间件平台。伏羲云原生游戏中间件平台基于Kubernetes技术,提供了基于容器的数据库、CacheServer、SymbolServer等游戏项目中的中间件服务,为游戏在开发、测试、上线各个阶段需要各种中间件支持,帮助游戏更好的专注于游戏本身。

云原生游戏中间件平台遇到的挑战

云原生游戏中间件平台作为服务于游戏业务的核心平台,面临着以下严峻的挑战:
  • 灵活性:各个游戏业务对基础服务使用存在差异,需要满足各个业务多样化的需求。
  • 稳定性:云环境中存在节点异常、网络IO抖动,磁盘IO抖动等各种情况,这些情况都有可能导致服务异常,基础服务直接影响上层业务的稳定性和项目的推进,因此如何保证服务的稳定性十分重要。
  • 故障自愈:由于各种异常情况,服务可能存在主动退出、或者被动退出的情况。当出现服务的情况,服务需要具备自愈能力,服务能够被快速重新拉起,并且保证服务中数据的不丢失,从而避免人工介入修复。
  • 易观测:中间件运行的过程中,运行日志,指标参数需要能被完善收集便捷的展示,帮助用户了解中间件服务运行的状态。
  • 中间件生命周期管理:中间件服务的生命周期管理就是对中间件的各个状态进行管理,各个状态具有对应可执行的操作。


云原生游戏中间件平台落地

在技术架构上,伏羲云原生游戏中间件平台核心基于Kubernetes进行构建,充分利用了Kubernetes提供的容器编排管理能力。利用Kubernetes Operator模式扩展Kubernetes API,将各个中间件服务抽象成Kubernetes中的资源进行管理。

整体架构

1.png

云原生游戏中间件平台分为:用户层、业务服务层、核心服务层以及基础设施层。

核心服务层作为平台的大脑提供了Kubernetes扩展自定义中间件资源的生命周期管理能力,以及中间件资源的可观测性等能力。

中间件生命周期管理

Kubernetes Operator模式

自定义资源(Custom Resource) 是对 Kubernetes API 的扩展,通过CRD(Custom Resource Definitions)动态注册自定义资源类型,并可以与Kubernetes内置资源对象(如 Pod、Deployment等)相同的方式来管理它们。CRD可以充分利用Kubernetes已有的能力,核心能力包括:Schema定义校验、多版本、status/scale子资源等。

CRD仅仅提供了自定义资源结构化数据的存储能力。为了使自定义资源成为声明式API(声明资源的期望状态,并尝试让Kubernetes对象的当前状态同步到其期望状态),资源达到期望状态的逻辑就需要CRD Controller来实现。

Kubernetes Operator模式是将CRD与CRD Controller相结合,实现自定义资源以及资源自动化运维。
2.png

云原生游戏中间件平台采用的是Operator模式管理游戏中间件服务,每一个游戏中间件对应一个Operator实现,通过Operator实现游戏中间件服务的生命周期管理,自动化运维。

中间件可观测性

中间件的可观测性作为中间件平台的核心能力,目的是帮助检测定位中间件服务的运行状态(例如:服务异常、错误、响应缓慢等)。服务观测主要包含日志和指标监控两个层面。

中间件服务日志收集

中间件服务的日志分为两种类型:

1、标准输出、标准错误输出日志收集方案
  • 实时标准输出、标准错误输出日志,业务服务层日志查询服务通过调用Kubernetes API获取中间件容器的实时标准输出、标准错误输出日志,然后展示到用户层。
  • 日志存储及检索,Kubernetes中容器重启等场景会使得日志丢失,因此需要将中间件容器的标准输出、标准错误输出日志持久化的进行存储,并且支持日志检索等需求。架构如下:
    3.png


中间件服务容器的标准输出、标准错误输出的日志会以文件的形式存储在Pod所在宿主机上。通过Kubernetes DaemonSet方式在各个节点上部署Fluentd,并采用hostPath方式将宿主机上容器日志挂载到Fluentd的Pod中。Fluentd将中间件容器的日志发送到Kafka,最终存储到ElasticSearch中。

2、容器内日志收集方案

在一些场景下中间件日志存储在容器中,不同中间件的日志文件命名也不相同。针对容器内日志收集架构如下:
4.png

容器内日志收集采用Sidecar模式中间件Pod中增加日志收集容器Filebeat,Filebeat容器与中间件容器的日志目录通过emptyDir挂载的方式实现目录共享。Filebeat根据ConfigMap定义的配置,将中间件日志发送到Kafka,最终存储到ElasticSearch中。

中间件服务监控

传统的以主机为中心的基础设施中,我们仅监控两个层次:中间件服务和运行它们的主机。而云原生平台监控包含四个维度:节点监控、Kubernetes资源状态监控、容器监控、游戏中间件服务监控。整体架构如下:
5.png

exporter通过RESTful API的方式暴露指标数据,Prometheus从各个exporter中拉取指标数据,并进行持久化存储。Alertmanager则是Prometheus内置的告警模块。这里主要介绍exporter实现四个维度监控。
  • 节点监控,节点的指标收集通过node exporter实现。node exporter通过DaemonSet方式部署在Kubernetes的每个节点上,用于采集节点的运行指标,包括节点CPU,内存,文件系统等指标。
  • Kubernetes资源状态监控,kube-state-metrics采用Deployment方式部署,通过监听Kubernetes apiserver将Kubernetes资源的数据生成相应指标。在云原生游戏中间件平台场景下,我们需要对自定义游戏中间件资源状态进行监控。
  • 容器监控,cAdvisor对节点容器进行实时监控和性能数据采集,包括CPU使用情况、内存使用情况、网络吞吐量及文件系统使用情况。cAdvisor以及集成在kubelet中,当kubelet启动时会自动启动cAdvisor。
  • 游戏中间件服务监控,上述监控从Kubernetes资源状态、节点、容器层进行,而更细粒度的就需要游戏中间件服务本身进行监控,不同游戏中间件需要监控的服务指标也不相同。游戏中间件平台层就需要针对各个中间件资源实现各自的exporter,从而达到服务级别的监控。


CacheServer中间件加速Unity开发

以上介绍了云原生游戏中间件平台落地的核心通用层面。然而各个游戏中间件具有不同的特点,为了更好的实现游戏中间件服务的灵活性、稳定性、以及故障自愈能力,就需要从Operator实现、CacheServer相关优化等深入考虑。

下面以CacheServer中间件为例,介绍如何实现云原生游戏CacheServer中间件。

CacheServer介绍

CacheServer是Unity的缓存服务器。网易基于Unity CacheServer v1协议,自研了CacheServer服务,CacheServer由Nginx作为入口,资源数据都存储在ARDB中。ARDB是一个类似Redis的KV存储,但相比Redis的优点就是数据都由底层的RocketsDB持久化存储在磁盘上,在Redis服务中只存储所有资源数据内容的key,以及在key上设置TTL,再由Cleaner Server负责清理。架构如下:
6.png

下文中出现的CacheServer即为网易自研CacheServer。

云原生CacheServer架构

7.png

上图是CacheServer是基于Kubernetes的云原生架构。CacheServer Pod包含了CacheServer容器和Cleaner容器。CacheServer容器提供了CacheServer核心服务能力包含了Nginx、CacheServer Server、ARDB和Redis服务。Cleaner容器以Sidecar的模式,提供缓存清理能力。ARDB数据以emptyDir方式进行挂载,随Pod生命周期。CacheServer Service提供Kubernetes的访问入口。

CacheServer Operator实现

CacheServer CRD定义:
type Cacheserver struct {  
metav1.TypeMeta   `json:",inline"`  
metav1.ObjectMeta `json:"metadata,omitempty"`  

Spec   CacheserverSpec   `json:"spec,omitempty"`  
Status CacheserverStatus `json:"status,omitempty"`  


type CacheserverSpec struct {    
Storage int64 `json:"storage"`  
Image string `json:"image"`  
Resources corev1.ResourceRequirements `json:"resources"`  
Cleaner Cleaner `json:"cleaner"`  
Tolerations []corev1.Toleration `json:"tolerations"`  
NodeSelector map[string]string `json:"nodeSelector"`  
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`  
}  

type CacheserverStatus struct {  
Phase string `json:"phase"`  
}  

type Cleaner struct {   
Webhook string `json:"webhook"`  
Image string `json:"image"`  


CacheServer CRD定义包含了三部分:
  • 基础信息:名称、Namepace、CacheServer镜像、Cleaner镜像、镜像拉取Secret等。
  • 资源配置:CPU、内存、持久化存储大小。
  • 调度:CacheServer Pod调度配置Tolerance、NodeSelector等。


CacheServer Operator实现逻辑:
8.png

CacheServer Operator分为资源管理和状态管理两个部分:
  • 资源管理:管理CacheServer所包含的Pod、Service等子资源。Operator通过list、watch监听CacheServer事件(创建、更新、删除),发送到Resource Handler的队列中,由控制循环取出事件并处理。创建资源时将子资源的OwnerReference设置成父资源,可以在删除CacheServer时利用kubernetes级联删除有效删除子资源。
  • 状态管理:实时更新CacheServer的运行状态。Operator通过list、watch循环监听CacheServer Pod资源,根据Pod运行状态,更新CacheServer的状态。


CacheServer优化

存储优化

CacheServer使用场景下对数据的读写性能要求非常高,arbd数据的持久化存储需要重点考虑。以往常用的网络存储Ceph Rbd等方案无法达到我们的性能要求。因此我们采用宿主机存储的方案。Kubernetes提供了hostPath、emptyDir、local volume等。
  • hostPath:映射宿主机文件系统中的文件或者目录到pod,需要数据清理等管理。local volume需要维护挂载点。本方案采用emptyDir的方式。
  • emptyDir:Pod分配到Node上时被创建,Kubernetes会在Node上自动分配一个目录,因此无需指定宿主机Node上对应的目录文件。
  • local volume:通过PVC方式访问宿主机的本地存储,但静态provisioner仅支持发现和管理挂载点,必须将它们通过bind-mounted的方式绑定到发现目录中。


本方案采用emptyDir的方式,emptyDir数据生命周期与Pod的生命周期是一致的。并设置Pod的QoS等级避免被驱逐,从而高效的管理管理CacheServer数据存储。

调度优化

CacheServer的资源数据上传下载会对网络、磁盘要求很高。为了避免多个CacheServer集中在一个节点上而相互影响,我们采用了Kubernetes的反亲和性特性,将CacheServer Pod进行节点维度的反亲和。下面设置CacheServer Pod反亲和性:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
    labelSelector:
      matchLabels:
         app.kubernetes.io/managed-by: cacheserver-operator
    topologyKey: kubernetes.io/hostname
  weight: 100

节点优化

针对CacheServer的特性,我们需要对宿主机的内核参数,以及硬件设备进行优化升级。
  • 内核参数优化:包括net.ipv4.tcp_sack,net.core.rmem_max,net.core.wmem_max,net.core.wmem_default,net.ipv4.tcp_mem,net.ipv4.tcp_rmem,net.ipv4.tcp_wmem等。
  • 硬件升级:磁盘使用SSD,提升ardb数据的读写能力。


未来展望

游戏云原生中间件平台后续将围绕着全面性、平台性、高性能、高可靠等继续推进。核心包括:
  • 支持更多的游戏中间件上云,为游戏提供更全面支持。
  • 游戏中间件Operator引擎:将游戏中间件特点进行抽象,Yaml定义的方式实现游戏中间件Operator通用特性,帮助快速实现游戏中间件Operator。
  • 游戏中间件调度:增加调度的维度,帮助中间件更合理的进行调度。提升资源利用率,和高性能等。


作者:三零,网易伏羲

0 个评论

要回复文章请先登录注册