乐趣区

关于大数据:vivo-在离线混部探索与实践

作者:来自 vivo 互联网服务器团队

本文依据甘青、黄荣杰老师在“2023 vivo 开发者大会 ” 现场演讲内容整顿而成。

随同 vivo 互联网业务的高速倒退,数据中心的规模不断扩大,老本问题日益突出。在离线混部技术能够在保障服务质量的同时,极大的晋升数据中心资源利用率,降低成本。混部技术波及任务调度、资源隔离、运维观测等一系列技术难题,本文将介绍 vivo 在混部技术方面的实际和摸索,为读者提供借鉴和参考

一、在离线混部技术背景

1.1 为什么混部

数据中心运行的服务能够分为在线服务和离线工作两大类,它们具备不同的资源应用特色。

在线服务是指那些长时间运行、对时延十分敏感的服务,如电商、游戏等,在线服务的资源利用率存在显著的波峰波谷景象,均匀利用率较低。离线工作是指那些运行周期短,有容错性,对实时性要求低的服务,如数据转换、模型训练等,离线工作在执行过程中资源利用率很高。

在混部之前,在线和离线都是离开独立部署,机器不共享,无奈造成无效的资源互补,这导致数据中心整体资源利用率不高,却要一直购买新机器,造成了资源节约。

1.2 混部技术定义

通过混部技术,咱们能够将在线和离线部署到同一台物理机上,造成资源互补,晋升物理机的资源利用率,降低成本。混部技术最早由谷歌在 2015 年提出,通过多年的倒退,混部技术曾经趋于成熟,目前业内利用混部技术能够将数据中心的 CPU 利用率晋升至 40% 左右。

vivo 在 2020 年开始调研混部技术,2023 年混部平台投入生产,目前咱们曾经将局部混部集群的 CPU 利用率晋升至 25%(最新已达 30%)左右。相较业界标杆这还有肯定的差距,但随着混部规模的扩充,咱们将挑战更高的指标。

二、在离线混部平台实际

2.1 混部平台产品能力

混部平台必须具备两个产品能力:

  • 第一、弱小的调度、隔离能力
  • 第二、欠缺的监控、运维能力

弱小的调度能力解决了,咱们如何将离线工作高效、正当的调度到在线服务所在的物理机上。而弱小的隔离能力保障了在线服务的品质不受离线工作烦扰。欠缺的监控和运维能力则能够让咱们洞悉整个混部平台的运行状况,及时发现潜在危险,帮忙运维人员更高效的实现零碎和业务的运维工作,保障集群的高稳定性。

2.2 混部差异化资源视图

混部首先要解决的一个问题是离线应用哪一部分资源。

在 vivo 混部零碎中在线和离线看到的资源视图是不同的:

  • 在线可用资源为 整机资源
  • 离线可用资源为 整机资源减去 在线理论应用的资源

同时为了防止整机负载太高影响零碎的稳定性,咱们设置一个平安水位线,用于调节离线可用资源大小。

2.3 混部 QoS 等级

为了保障混部零碎的 slo,咱们将服务分为三个等级:高、中,低

不同等级的服务对物理资源如:CPU、内存 应用时有不同的优先级。高优先级服务反对绑定 CPU 模式,实用对延时十分敏感的在线服务。个别的在线服务可设置为中优先级。离线工作设置为低优先级,通过这样的等级划分,咱们很好的实现在线对离线的资源压抑和隔离,保障了在线服务质量。

2.4 混部外围组件架构

咱们所有的混部组件都是以插件形式独立运行,对原生 K8s 无侵入。咱们实现了一个混部调度器,在线和离线对立应用这个调度器,防止了多调度器资源账本抵触的问题。

每台物理机上都会部署一个混部 agent,它能够实时采集容器资源应用数据,并依据平安水位线对离线工作进行压抑、驱赶等操作。

内核层面咱们应用了龙蜥 OS,它具备弱小的资源隔离能力,能够帮忙咱们更好的隔离在线、离线资源应用,保障在线服务质量。

2.5 混部组件性能

咱们把混部组件分为管控组件和单机组件两大类。

管控组件 次要负责调度和管制,依据 vivo 业务应用场景,咱们对调度器做了一些加强,提供了 numa 感知、负载感知,热点打散,批量调度等能力。

混部控制器次要提供了一些配置管理能力:如资源画像统计、node slo 配置、node 扩大资源变更等。

2.6 混部可视化监控

咱们为混部建设一套残缺的可视化监控体系。

针对在线服务咱们提供了:容器资源应用指标,受离线烦扰指标、业务混部收益指标等监控能力。

针对离线工作,咱们提供了离线可用资源、工作异样状态等监控能力。

在平台层面上咱们提供了节点、内核,外围组件的监控,通过这些监控可及时发现平台潜在的危险。

2.7 混部平台运维

为了简化运维操作,晋升运维效率,咱们对混部集群搭建和节点扩缩容操作进行了白屏化革新,开发了资源池治理性能,简化了物理机接入流程,运维效率大幅晋升。

在运维平台上运维人员能够疾速调整混部隔离、水位线等参数,如果发现在线服务受到烦扰,运维人员能够一键敞开混部,驱赶离线工作,保障在线服务质量。

2.8 问题与挑战

2.8.1 apiServer 拆分

通过混部产品能力的建设,咱们很好的实现了容器混部能力,然而在实践中咱们还是遇到一些新的挑战:绝对于一般 K8s 集群,混部集群中运行着更多的容器,而且离线工作因为生命周期短,容器创立销毁更为频繁,这对 K8s apiServer 产生了很大的压力。

所以咱们拆分了 apiServer,离线工作应用独立的 apiServer,保障了集群 apiServer 负载始终处于一个平安程度。

2.8.2 监控架构优化

同样混部之后因为采集了更多的监控指标,导致 Prometheus 内存耗费过多,无奈满足平台指标 采集需要。针对这个问题,咱们优化了监控架构,将在线和离线监控组件离开部署,离线改用性能更好的 vmagent,通过这个优化,监控组件内存耗费缩小到原来的十分之一。

2.9 利用率晋升

混部初期尽管集群 CPU 利用率有所晋升,然而还是没有达到咱们的预期,次要 起因 有:

  • 一、局部低配置机器资源自身较少。
  • 二、Java 类利用堆会固定占用大量内存,导致可提供给离线应用内存资源有余。

针对这些问题,咱们开发了定时调整平安水位线性能,在业务低峰期上调平安水位线,开释更多的资源给离线应用。通过一系列的优化伎俩,咱们将其中一个混部集群的 CPU 利用率由 13% 晋升到了 25% 左右,简直翻倍,混部成果失去了无效的验证。

三、Spark on K8s 弹性调度实际

3.1 计划选型

在大方向的技术选型上,咱们抉择了 Spark on K8s,在业内,也有一些公司采纳了 YARN on K8s 的计划。咱们也对这两种计划进行过比照。

从业务适用性来说,YARN on K8s 是通用的,能够兼容 Hive、Spark、Flink 这些引擎,它不须要频繁创立 Nodemanager pod,对 K8s 的压力比拟小。这些都是它的长处,但另一方面,Nodemanager ESS 服务是对磁盘有容量和读写性能要求的,混部机器磁盘个别难以满足。所以咱们要反对不同引擎的 remote shuffle service。

如果计算引擎有不同的版本,那么 RSS 也要反对不同版本,比方 Spark2,Spark3。如果你有不同的引擎,不同的版本,很可能一种 RSS 还满足不了需要。另外 Nodemanager 须要依据 K8s 混部节点的残余资源,动静调整可用的 vcore 和内存,所以还须要一个额定的组件来做这个事件,这须要较高的革新老本。在资源利用上,NM 的资源粒度绝对大,本身也会占用一些资源,存在肯定的节约。在资源缓和的状况下,Nodemanager 作为整体被驱赶,会影响多个工作。这些是 YARN on K8s 的劣势。

作为比照,Spark on K8s 劣势有哪些?

首先这个个性在 Spark 3.1 以上版本才正式可用。Spark on K8s 因为会频繁的创立、查问、销毁大量的 executor pod,对 K8s 的调度能力以及 master 节点会造成比拟大的压力。另一方面,它的劣势在于只须要能反对 spark3.X 的 RSS,这有较多的开源产品可抉择。而且革新老本比拟低,不须要额定的组件。资源粒度小,更有利于充分利用集群资源。在资源缓和时,会一一 pod 进行驱赶,工作的稳定性会更高。

两计划各有优劣势,为什么咱们抉择了 Spark on K8s?一方面因为 Spark3.X 是 vivo 以后及将来 2~3 年的支流离线引擎,另一方面 vivo 外部对 K8s 研发比拟深刻,能无力反对咱们。基于以上起因,咱们最终决定应用 spark on K8s

3.2 三步走策略

确定了计划选型,那在 vivo 咱们是如何推动 spark on K8s 大规模的利用落地呢?回顾总结咱们走过的路,能够大抵演绎为三步走的策略。

  • 第一,是工作跑通跑顺的初期阶段
  • 第二,是工作跑稳、跑稳的中期阶段
  • 最初,是工作跑得智能的成熟阶段

接下来的内容,咱们将对每个阶段开展细说。

3.2.1 工作跑通跑顺

在工作跑通、跑顺的第一阶段,咱们要解决的是怎么将工作提交 K8s 集群,同时要求易用性、便利性方面可能达到与 on YARN 统一的用户体验。将咱们最初采纳的计划架构简化一下,就如同这张图所示。

首先,为了升高工作提交的复杂性、防止用户革新工作的老本。咱们在任务调度治理平台做到了对原有 Spark 工作的兼容,通过 vivo 外部的容器凋谢 API- 这个代理层,咱们不须要保护额定的 K8s client 环境,就能够轻松实现工作提交,提交后也能近实时获取工作的状态和日志信息。

另外一个关键点是,咱们选用了 Spark Operator 作为 Spark 工作容器化的计划。Spark Operator 是谷歌基于 K8s Operator 模式开发的一款的工具,用于通过申明式的形式向 K8s 集群提交 Spark 作业。

Spark Operator 的形式还有其余长处:

  • Operator 形式对 K8s 更敌对,反对更灵便、更全面的配置项
  • 应用上更简略易用
  • 内置 Metrics, 有利于咱们做集中管理

要达到阶段一的指标,让工作跑通、跑顺。咱们次要克服了哪些 关键问题和挑战

第一个是日志查看,因为 Spark Operator 形式并没有提供已完结作业的日志查看形式,包含 driver 和 executor 日志。在 Driver 侧,咱们通过定期申请容器凋谢 API,能准实时地获取 Driver Pod 状态与日志。在 Executor 侧,咱们参考了 on yarn 的形式,Executor Pod 完结后,日志上传 HDFS,与 YARN 日志聚合相似。

另一方面,咱们也在 Spark HistoryServer 做了二次开发工作,减少了 on K8s 形式的日志查看接口。用户查看已实现的 Executor 日志时,不再申请 JobHistory Server,而是申请 Spark HistoryServer 接口。在体验上做到了根本与 yarn 统一。

在混部 K8s 集群,咱们也做了三方面能力的 增强

  • 一是,确保调配能力能反对离线工作频繁建删 pod 的需要,在优化后咱们离线 Pod 调配能力达到数百 pod/ 秒。
  • 二是,在 K8s 侧晋升了 spark 外部的 Driver 优先级,确保了在驱赶时 Driver 稳定性高于 Executor。
  • 最初一个是,发现并修复了 spark-operator 的一个 bug,这个 bu 是 Operator 在多正本部署时,slave 正本 webhook 解决有一点概率呈现 pod 找不到的问题。

3.2.2 工作跑稳跑准

在第二阶段,咱们要保障的是工作跑稳,数据跑准, 因而,咱们有两个 要害的动作

  • 大规模双跑,目标是确保 Spark 工作迁徙到 K8s 集群后是兼容的,工作成功率有保障;工作执行时长是稳固的,不会显著变慢;数据是精确的, 跟 on YARN 放弃一致性。为此,咱们须要对工作进行 on YARN 和 on K8s 两种模式下的双跑测试,咱们分批次总共进行了 7 轮双跑,笼罩了 2 万 + 的线上正式工作。最终也获得了咱们想要的后果:咱们双跑最终达成的工作成功率超过了 99.5%,绝大部分的工作在两种模式下的时长稳定在 25% 以内,数据一致性是 100%。
  • 混部集群的压力联调,目标是确保混部集群的承载容量可能撑持大规模的离线任务调度,通过模仿将来 1 年的任务量来给混部集群做压力测试,充沛发现和检测 K8s 集群可能存在的性能问题。最终,通过咱们多轮压测和问题解决,咱们在单个 K8s 集群可能撑持 150+ 同时运行的 Spark 工作,1 万 + 同时在运行的 Pod 数量。

第二阶段 ,咱们次要面临三个方面的 问题和挑战

首先是咱们须要为 Spark 抉择一个内部的 shuffle 服务,通过技术选型和比拟,咱们最终抉择开源的 celeborn 作为咱们的 remote shuffle service 组件。咱们通过对机型和参数的测试调优,使 celeborn 的性能达到咱们的预期需要。在大规模的利用场景中,咱们还发现了会存在大工作会阻塞小工作,导致 shufle read 变慢的问题,咱们对这种状况做了参数和代码上的优化,以后社区也针对 shuffle read 的问题有一些待优化的改良。另外 celeborn 进行了容器化部署,在晋升自动化运维能力的同时,也能够为混部集群提供额定的计算资源。

其次,在工作稳定性方面,咱们也解决了一系列的问题。

  1. 在双跑的时候,咱们发现有不少工作在 on K8s 模式下很容易 OOM,这是因为在 on YARN 模式下申请的 container 内存大小,不止是由 Spark 工作自身的内存参数决定,还会被 YARN 的资源粒度参数所影响。所以这块要做一些适配对标工作。
  2. 在任务量比拟大的状况下,Spark operator 的吞吐能力会遇到瓶颈,须要咱们将并发 worker 数量、队列的相干参数调大。
  3. CoreDNS 因为 Spark 工作频繁的域名解释申请,导致压力增大,甚至可能影响在线服务。这个能够通过拜访 ip 而不是域名的形式来躲避,比方 namenode 节点、driver 和 executor。
  4. 横向扩大 namespace,这样能够防止单 namespace 的瓶颈,也避免 etcd 呈现问题。
  5. 咱们 K8s apiserver 的压力随着任务量增长压力也会逐步增大,这会影响整个集群的稳定性。咱们次要通过优化 Spark driver list pod 接口、应用 hostnetwork 形式两个优化伎俩,无效升高了 apiserver 的压力。

最初要说的是数据一致性,关键点是要做到行级记录的 MD5 校验,发现有不统一的 Case,咱们做到 100% 的剖析笼罩。排除了因为工夫戳随机函数等一些预期内的不统一,咱们发现并修复两种 case 会偶发导致不统一的问题:

  • celeborn Bug 导致不统一,具体可参考 CELEBORN-383 解决
  • Java 版本不统一导致的问题

3.2.3 工作跑得智能

第三阶段,咱们须要解决的问题是让工作跑得智能,怎么定义智能,我想用三个词来概括弹性、强壮、业务需要。这是咱们弹性调度的架构图,细节我就不讲了,这里我介绍下咱们的调度零碎重点反对的性能。

在弹性方面,咱们须要做到实时依据混部集群资源闲忙,智能提交至混部集群或者 Hadoop 集群。在后期咱们 K8s 集群的资源绝对 Hadoop 是小头,通过正当的水位线管制,避免大量工作同时调度到 K8s 导致饿死。

强壮,就是要保障工作的高可用。

咱们建设的能力包含:

  • 工作双跑胜利后再混部
  • 反对离线工作失败主动回滚到 Hadoop 集群执行
  • 反对用户自主决定工作是否可调度至 K8s 集群
  • 初期剔除重要外围工作、剔除不可重试工作

目标是在用户工作迁徙时做到让用户无感。

在满足业务需要方面,咱们反对优先调度本业务的离线工作,优先满足业务部门的离线工作资源需要;反对只在指定时间段里调度离线工作,反对在出现异常状况下一键终止调度 K8s。这些是为了确保在线服务的高可用性,罢黜在线业务的后顾之忧。

3.3 混部成果

克服了三步走过程中的磕磕碰碰,咱们终于能够将离线工作大规模混布到 K8s 混部集群了。然而咱们很快发现,混部集群的整体利用率并没有达到咱们的预期,次要有三方面的 起因

  1. 初期的 Spark 工作有余,这个咱们通过放慢双跑,迁徙低版本的 Spark 工作,迁徙 Hive SQL 工作来解决。
  2. 在混部的时候,咱们也察看到,离线工作的 pod cpu 利用率其实没那么高。比方咱们申请一个核,通常只能利用 0.6 个核,存在节约的状况。咱们上线了 CPU 资源超分的能力,目前是动态的固定比例超分,通过这个措施,咱们能将 pod 的理论 cpu 利用率打到 80% 以上。
  3. 另外就是混部集群中的机器配置不均,局部机器 cpu 资源短缺,然而内存不够。咱们通过在调度侧管制可调度工作的资源粒度,尽量调度对内存资源需要较小的工作。

通过咱们在任务调度侧,以及之前甘青提到过的其余措施。混部集群利用率失去了进一步的晋升。

最初,我向大家同步下,以后咱们达成的 混部成果

咱们目前可供调度的工作靠近 2 万个,这些工作每天调度的次数曾经超过了 4 万次。在凌晨的高峰期,咱们通过混部,能为离线工作额定减少 2 万核、50TB 内存的计算资源。这个收益是相当可观的,咱们也心愿在将来的 2 到 3 年,将可调度的工作规模晋升到 6 万个,弹性资源可能为离线计算总资源奉献 20% 的份额。

通过持续深度推动在离线混部技术,咱们冀望可能为 vivo 增效降本工作继续地贡献力量。

以上就是本次分享的全部内容。

退出移动版