更多内容关注微信公众号:fullstack888
1、背景
2018 年底,vivo AI 研究院为了解决统一高性能训练环境、大规模分布式训练、计算资源的高效利用调度等痛点,着手建设 AI 计算平台。经过两年的持续迭代,平台建设和落地取得了很大进展,成为 vivo AI 领域的核心基础平台。平台从当初服务深度学习训练为主,到现在演进成包含 VTraining、VServing、VContainer 三大模块,对外提供模型训练、模型推理和容器化能力。VContainer 是计算平台的底座,基于 Kubernetes 构建的容器平台,具备资源调度、弹性伸缩、零一混部等核心能力。VContainer 容器集群有数千个节点,拥有超过 100PFLOPS 的 GPU 算力。集群里同时运行着上千个 VTraining 的训练任务和上百个 VServing 的推理服务以及数百个在线服务项目。本文主要分享了 VContainer 容器平台在服务弹性伸缩部署方面的实践和落地。
2、整体架构
业务容器化之后可以使用容器在服务器上高密度部署,以此提高集群整体的资源利用率。业务稳定运行一段时间之后,我们发现集群整体的资源利用率仍然存在巨大的提升空间,当前集群资源使用主要有以下问题:
(1)在线服务申请资源时考虑到突发流量和服务稳定性,预留大量的 buffer 资源,造成资源申请量普遍远超实际使用量。
(2)大部分在线服务的潮汐现象、波峰波谷特征非常明显,保留过多常态资源造成巨大浪费。
(3)开发和运维评估和配置的资源规格不合理,并且动态更新不及时。
为了进一步提升集群整体的资源利用率、降低服务器成本,我们调研了 kubernetes HPA 弹性伸缩并进行了落地实践。
kubernetes 将业务运行环境的容器组抽象为 Pod 资源对象,并提供各种各样的 workload(deployment、statefulset 等)来部署 Pod,同时也提供多种资源对象来解决 Pod 部署过程中的弹性伸缩和资源供给问题。
2.1 kubernetes autoscaling
kubernetes autoscaling 提供多种机制来满足 Pod 自动伸缩需求:
(1)Pod 级别的自动伸缩:包括Horizontal Pod Autoscaler(HPA)和Vertical Pod Autoscaler(VPA)。其中 HPA 会基于 kubernetes 集群内置资源指标或者自定义指标来计算 Pod 副本需求数并自动伸缩,VPA 会基于 Pod 在 CPU/Memory 资源历史使用详情来计算 Pod 合理的资源请求并驱逐 Pod 以更新资源配合;
(2)Node 级别的自动伸缩:Cluster Autoscaler(CA)会综合考虑 Pod 部署挂起或集群容量等信息确定集群节点资源并相应调整集群 Node 数量。
本文聚焦于 kubernetes 集群 Pod 级别的弹性伸缩实践和落地。
2.2 KEDA
kubernetes HPA 原生支持依据 CPU/Memory 资源利用率弹性伸缩,并在 autoscaling/v2beta2 版本中通过custom.metrics.k8s.io API 支持基于自定义资源的弹性伸缩。在 HPA 实践落地过程中,仅仅依赖 CPU/Memory 利用率弹性伸缩无法满足业务在多指标扩缩、弹性伸缩稳定性方面的诸多需求,为此,我们重点调研了 kubernetes HPA 自定义指标弹性伸缩。开源社区主要有 2 个相关项目,一个是 prometheus-adapter,另外一个是KEDA,最终我们采用 KEDA 作为弹性伸缩系统的基座,主要考虑到如下优势点:
(1)功能丰富:内嵌 CPU/Cron/Prom 多种伸缩策略,原生支持缩容至零;
(2)扩展性好:解耦被伸缩对象(支持/scale 子资源即可)和伸缩指标,提供强大的插件机制和抽象接口(scaler + metrics adapter),增加伸缩指标非常便利;
(3)维护性好:设计简洁、功能统一、组件单一提供良好的可维护性;
(4)社区强大:CNCF 官方项目,微软和 RedHat 强力支持。
我们基于 KEDA 构建 kubernetes 集群弹性伸缩系统,整体流程图如下所示:
(1)集群 Pod 部署会采用多种 workload(deployment、argoRollout、statefulset 等),KEDA 均支持这些伸缩对象,最终实际生效对象其实是/scale 子资源;
(2)所有的弹性伸缩对象统一使用 KEDA 管理,包括 HPA 内置支持的 CPU/Memory 利用率弹性伸缩、自定义指标弹性伸缩。我们基于 KEDA 强大的插件机制扩展支持了业务亟需的 GPU 利用率弹性伸缩和 HTTP/RPC QPS 弹性伸缩;
(3)测试集群和预发集群部署业务默认开启缩容至零特性,以此自动回收长期闲置的测试服务所占用的计算资源;
(4)基于 KEDA 在自动伸缩多策略、扩缩时效性、扩缩耗时、成功率、监控告警等稳定性方面做了一系列工作
3、多指标弹性伸缩
业务方在发布平台做业务部署时,可以直接白屏化配置合适的弹性伸缩策略,整体界面如下所示:
弹性伸缩策略整体分为两大部分:
(1)常规弹性伸缩:包括 CPU 利用率、内存利用率、GPU 利用率、平均 QPS,并且伸缩策略都支持配置 伸缩区间(最小副本数 <= 伸缩目标副本数 <= 最大副本数)。
(2)定时伸缩:资源使用具有强周期规律、潮汐特征明显的业务可以配置定时伸缩,应用副本数在对应时间段内保持在指定数量。
3.1 CPU/Memory 默认弹性伸缩
CPU/Memory 弹性伸缩中,我们只使用平均利用率类型的伸缩指标,整体数据流程如图所示:
3.2 Cron 定时伸缩
互联网在线业务通常都有明显的流量波峰波谷现象,潮汐特征非常明显,针对这种资源使用具有周期规律的业务,我们通常采用定时伸缩。
kubernetes HPA 计算 ExternalPerPodMetric 副本数:当前利用率/每个 Pod 目标利用率
KEDA CronHPA 中 将 "每个 Pod 目标利用率" 硬编码固定为 1,当前利用率 设置为 定时扩缩容时间段的副本数。这个巧妙的设计可以将普通的资源利用率弹性伸缩和定时伸缩统一起来,非常便利。
3.3 GPU 弹性伸缩
集群部分业务会使用 GPU 资源做 AI 模型推理计算,这种场景下业务方重点关注 GPU 利用率,希望可以基于 GPU 资源利用率做动态伸缩。我们基于 KEDA scaler 插件机制开发了 gpu-scaler,很好的满足了业务方需求。
GPU 弹性伸缩中整体数据流程如图所示:
3.4 QPS 弹性伸缩
集群部分业务方重点关注服务 QPS(HTTP/RPC),希望可以基于服务 QPS 做动态伸缩。我们基于 KEDA scaler 插件机制开发了 qps-scaler,很好的满足了业务方需求。
QPS 弹性伸缩中整体数据流程如图所示:
4、缩容到零
业务方在 CICD 发布平台进行流水线部署通常涉及多个运行环境,通常有测试环境 → 预发环境 → 生产环境,其中测试环境主要用来开发联调,预发环境主要用来小流量验证和预部署校验。
业务方在生产集群部署业务之后,测试环境和预发环境的实例副本通常会闲置,这会浪费一部分的计算资源,尤其是使用到 GPU 稀缺资源的业务。为此,我们在测试环境和预发环境默认开启了缩容到零特性,缩容规则如下:
4.1 Java 业务
当且仅当业务容器 同时满足以下条件:
a 容器创建时间点至今 大于 48 小时,即 2 天之内新部署的服务不会缩容到零;
b 基于请求数做缩容到零:PaaS 调用链查询 API 获取的 64 小时内请求总数 等于 0,即 64 小时内业务在调用链系统内无任何请求数据;
4.2 GPU 业务
当且仅当服务容器 同时满足以下条件:
a 容器创建时间点至今 大于 48 小时,即 2 天之内新部署的服务不会缩容到零;
b 基于 GPU 利用率做缩容到零:容器平台 prometheus 获取的 2 天内 GPU 利用率峰值 小于 1%,即 2 天内业务 GPU 利用率峰值小于 1%;