网易伏羲 三零 分布式实验室
网易伏羲成立于2017年,是国内专业从事游戏与泛娱乐AI研究和应用的顶尖机构。为了更好的为游戏提供中间件服务支持,伏羲云计算团队构建了伏羲云原生游戏中间件平台。本文主要介绍伏羲云原生游戏中间件平台的实践过程。
背景与场景
游戏是网易的核心业务。在游戏项目中,从游戏的开发、测试、到上线各个阶段都具有各种中间件的需求。在此背景下,对我们如何为游戏提供高效、可靠的中间件服务提出巨大的挑战。
传统的方式是通过运维人员手动搭建维护,而这种方式主要存在下面问题:
环境依赖:服务可能会因为基础环境的变化导致异常情况。
缺少标准化:各个游戏项目对中间件的使用方式存在差异。
缺少平台统一动态管理:缺少统一平台进行创建、删除等自主运维能力。
服务可靠性低:服务不可用等状态难以及时发现,以及人工修复效率比较低。
为了解决这些问题,伏羲云计算团队构建了云原生游戏中间件平台。伏羲云原生游戏中间件平台基于Kubernetes技术,提供了基于容器的数据库、CacheServer、SymbolServer等游戏项目中的中间件服务,为游戏在开发、测试、上线各个阶段需要各种中间件支持,帮助游戏更好的专注于游戏本身。
云原生游戏中间件平台遇到的挑战
灵活性:各个游戏业务对基础服务使用存在差异,需要满足各个业务多样化的需求。
稳定性:云环境中存在节点异常、网络IO抖动,磁盘IO抖动等各种情况,这些情况都有可能导致服务异常,基础服务直接影响上层业务的稳定性和项目的推进,因此如何保证服务的稳定性十分重要。
故障自愈:由于各种异常情况,服务可能存在主动退出、或者被动退出的情况。当出现服务的情况,服务需要具备自愈能力,服务能够被快速重新拉起,并且保证服务中数据的不丢失,从而避免人工介入修复。
易观测:中间件运行的过程中,运行日志,指标参数需要能被完善收集便捷的展示,帮助用户了解中间件服务运行的状态。
中间件生命周期管理:中间件服务的生命周期管理就是对中间件的各个状态进行管理,各个状态具有对应可执行的操作。
云原生游戏中间件平台落地
整体架构
云原生游戏中间件平台分为:用户层、业务服务层、核心服务层以及基础设施层。
核心服务层作为平台的大脑提供了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相结合,实现自定义资源以及资源自动化运维。
云原生游戏中间件平台采用的是Operator模式管理游戏中间件服务,每一个游戏中间件对应一个Operator实现,通过Operator实现游戏中间件服务的生命周期管理,自动化运维。
中间件可观测性
中间件的可观测性作为中间件平台的核心能力,目的是帮助检测定位中间件服务的运行状态(例如:服务异常、错误、响应��: ţ��װ��ţ�п㡢ţ�з���������ñ�����й�ӡȾ�����ٶ������ۡ���֯Ʒ��ëƤ�����¡���ŮƤЬ��Ѽ��������졢�������¡���ͳ�ࡢë��֯ҵ���� ˿��װ�������ס����ס����ࡢӡȾ�����й�˿�����֡�Ь�ǡ����ӡ�����ɴ������������ë������֯��Ʒ����֯ӡȾ����������ᡢëƤ��װ��DZˮ������ë����IJ���Ůʽ��װ�������ޡ���ë���㡢Χ�����������ë������Ь����ҵ���˶������Ʒ�����Ь��Ьҵ���ߵ�ʱװ��ʱװ��Ůʿ���¡�ʱ�С����¡��ڿ㡢Ƥ���ס����ӡ�Ь�ࡢñ�ӡ���ͷЬ������ñ��ձ��Ь�桢�������װ�ӹ���ë�ϡ�ͯװ����ë�����ë����˾�ס���ë�ߡ�����ë��Ƥѥ�����롢缓慢等)。服务观测主要包含日志和指标监控两个层面。
中间件服务日志收集
中间件服务的日志分为两种类型:
1、标准输出、标准错误输出日志收集方案
实时标准输出、标准错误输出日志,业务服务层日志查询服务通过调用Kubernetes API获取中间件容器的实时标准输出、标准错误输出日志,然后展示到用户层。
日志存储及检索,Kubernetes中容器重启等场景会使得日志丢失,因此需要将中间件容器的标准输出、标准错误输出日志持久化的进行存储,并且支持日志检索等需求。架构如下:
中间件服务容器的标准输出、标准错误输出的日志会以文件的形式存储在Pod所在宿主机上。通过Kubernetes DaemonSet方式在各个节点上部署Fluentd,并采用hostPath方式将宿主机上容器日志挂载到Fluentd的Pod中。Fluentd将中间件容器的日志发送到Kafka,最终存储到ElasticSearch中。
2、容器内日志收集方案
在一些场景下中间件日志存储在容器中,不同中间件的日志文件命名也不相同。针对容器内日志收集架构如下:
容器内日志收集采用Sidecar模式中间件Pod中增加日志收集容器Filebeat,Filebeat容器与中间件容器的日志目录通过emptyDir挂载的方式实现目录共享。Filebeat根据ConfigMap定义的配置,将中间件日志发送到Kafka,最终存储到ElasticSearch中。
中间件服务监控
传统的以主机为中心的基础设施中,我们仅监控两个层次:中间件服务和运行它们的主机。而云原生平台监控包含四个维度:节点监控、Kubernetes资源状态监控、容器监控、游戏中间件服务监控。整体架构如下:
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开发
CacheServer介绍
CacheServer是Unity的缓存服务器。网易基于Unity CacheServer v1协议,自研了CacheServer服务,CacheServer由Nginx作为入口,资源数据都存储在ARDB中。ARDB是一个类似Redis的KV存储,但相比Redis的优点就是数据都由底层的RocketsDB持久化存储在磁盘上,在Redis服务中只存储所有资源数据内容的key,以及在key上设置TTL,再由Cleaner Server负责清理。架构如下:
下文中出现的CacheServer即为网易自研CacheServer。
云原生CacheServer架构
上图是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实现逻辑:
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。
游戏中间件调度:增加调度的维度,帮助中间件更合理的进行调度。提升资源利用率,和高性能等。