本文整理自字节跳动基础架构工程师邵凯阳、林友权在 2022 Hadoop Meetup 上的演讲,文章主要从演进背景、解决方案、上线收益和未来规划四个方面介绍了字节跳动 YARN 云原生化演进实践。
作者|字节跳动基础架构工程师-邵凯阳、字节跳动基础架构工程师-林友权
演进背景
字节跳动(以下简称字节)内部离线业务具有庞大的规模,线上每天有数十万节点运行,每天的任务数达到百万量级,每天使用的资源量达到千万核量级。在如此庞大的计算规模下,为了能够高效地处理任务,提高资源流转效率,调度系统发挥了非常重要的作用。
如上图所示,我们可以清楚地看到,字节内部调度架构分为两大块 ——
离线调度
系统和
在线调度
系统,离线调度系统主要负责离线资源管理和离线任务调度,在线调度系统主要负责在线资源管理和在线任务调度。
为了提高字节内部整体的资源利用率,我们也进行了
混部
技术
的
探索
。主要思路是在在线的节点上同时部署 Kubelet
和 NM 服务,当在线节点比较空闲时可以及时将空闲资源出让给离线业务使用,以此使得整个数据中心的资源利用率能够得到比较大的提升。
但随着公司内业务规模
的持续发展
,这一套系统也暴露出了
一些
短板
:
综上所述,
字节内部有
三个核心诉求:
为了实现上述诉求,我们进行了一些思考和探索。其中一种解决方案是:
能不能让离线作业直接迁移
到
Kubernetes
?即:大数据生态下的各个计算引擎(包括:Spark、Flink 等)进行深度改造去适配 Kubernetes。在探索过程中发现这种方式有比较大的缺陷,主要有以下三点:
基于以上思考,我们提出了一种全新的
解决
方案
——
Yodel。Yodel 的全称是 YARN on Gödel(Gödel 是公司内部增强版 Kubernetes,它对 API Server、Gödel 调度器以及底层运行时都进行了增强),是字节跳动提出的 Hadoop YARN 云原生化演进实践方案。通过 Yodel 我们将公司内的大数据业务(Spark、Flink 等)、训练业务(Primus)平滑迁移到了 Kubernetes ,实现了在离线资源池统一,提升了整体资源利用率。
解决方案
下面将从 Yodel 整体架构、Remote Godel Scheduler(RGS) 服务、Remote Kubelete Service(RKS) 服务、持久化服务、平滑迁移及重要优化六个方面来详细介绍我们的解决方案。
Yodel 整体架构
Yodel 基于 YARN 实现,新增 ZK/ETCD/KV State Store、Remote Godel Scheduler 、Remote Kubelet Service 服务。ZK/ETCD/KV State Store 主要用于持久化存储、Remote Godel Scheduler 维护资源请求并与 API Server 交互,将调度能力统一到 Godel Scheduler;Remote Kubelet Service 实现了 YARN NM 所有接口,对用户和作业透明的前提下,把 NM 的 Container 管理能力平滑下沉到 Kubelet。
Yodel
整体架构图
从上面的架构图可以清楚看到 Yodel 的整体架构, 图中蓝色组件是进行了适配改造的组件,蓝色中标红的组件是新增组件,黄色组件是 Gödel 生态下的组件,
关于新增组件:
下面介绍在
Yodel
架构下一个离线任务的提交和运行流程
:
-
用户从开发机或任务托管平台向集群提交一个任务;
-
当任务经过校验后,Yodel RM 会新建一个 App 对象并持久化至 API Server;
-
Yodel RM 创建 AM Pod 并写入 API Server,等待底层调度器调度;
-
Yodel RM 收到已经调度完成的 AM Pod 并进行相关转化操作;
-
Yodel RM 将相关启动信息丰富至 AM Pod 中并 Patch 至 API Server 由 Kubelet 拉起相关进程;
-
AM 启动成功后,随心跳主动向 Yodel RM 申请资源;
-
Yodel RM 收到任务的资源请求后,通过 RGS 服务将资源请求转化为 Pod 对象或 PodGroup 对象并写入到 API Server;
-
底层调度器 Watch 到相关对象后,按照一定策略进行调度,同时 Yodel RM 也会及时地 Watch 到已经调度的 Pod;
-
Yodel RM 会将已经调度的 Pod 转化为 Container,随心跳返回给对应的 AM;
-
AM 收到已经调度的 Container 后,会再跟 Yodel RM 进行交互,来启动对应的容器;
-
Yodel RM 收到容器启动请求后,通过 RKS 服务将容器启动所需要的信息丰富到 Pod 对象里并 Patch 到 API Server。Kubelet Watch 到待启动的 Pod 后,会进行这个 Pod 的启动;
Yodel
架构
Pod
生命周期
上面讲了 Yodel 架构下任务的启动流程,下面我们来看一下
对于一个
Pod
来说,它的生命周期是怎么样的
,核心流程如上图所示:
-
首先,AM 启动起来后会随心跳申请资源;
-
Yodel RM 收到资源请求后,会基于该资源请求的资源量、优先级等创建一个 Pod 对象写入 API Server。创建完成后,该 Pod 对象处于 Pending-Unscheduled 状态,等待底层调度器进行调度;
-
底层调度器 Watch 到新创建的 Pod 后,根据一定策略进行调度,调度完成后会将调度结果写入 API Server。写入完成后,该 Pod 对象的状态会变为 Pending-Scheduled 状态;
-
Yodel RM Watch 到已经调度完成的 Pod 后会转化为 Container,该 Pod 对象的状态会变为 Allocated 状态;
-
新分配的 Container 会随心跳返回给 AM,Container 被对应 AM 拿走后,该 Pod 对象的状态会变为 Acquired 状态;
-
AM 获取到容器后会与 Yodel RM 交互进行启动操作;
-
Yodel RM 收到容器拉起请求后,会把容器启动所需的信息填充到 Pod 对象中并 Patch 到 API Server ;
-
Kubelet Watch 到需要启动的 Pod 后,会启动相关进程,容器运行时由 Kubelet 维护;
Remote Godel Scheduler
下面来介绍调度模块比较重要的一个服务 —— RGS 服务。由上图可以看到,
RGS 服务主要分为三大部分:
通过上述
各个服务的协调配合,
Yodel
能够实现:
Remote Kubelet Service
接下来介绍 RKS 服务
。RKS 部署在 Yodel RM 内部,实现了 YARN NM 的所有接口,把 NM 的 Container 管理能力平滑下沉到 Kubelet
。它主要由两部分组成:
此外,为了补齐 NM 上的运行体验,底层以 daemonset 方式部署了一些其他服务。这些 daemonset 补齐了 NM 的能力,使得离线作业只需要升级 hadoop 依赖,不用做太多改动,就能让容器运行在 Kubelet 上。这些服务包括:
下面看一个容器是怎么运行在
Kubelet
上的:
-
改造了 NM Client SDK,使 AM 调用 startContainer 时能直连 RKS;
-
RKS 收到启动请求后,会把 containerLaunch 上下文等信息写入到 Pod 并 Patch 到 API Server;
-
Kubelet Watch 到离线 Pod 后,会通过本机的 LocalizationService 下载 Pod 对应的 HDFS 资源;
-
下载完成后, Kubelet 通过 Containerd 把对应的 HDFS 资源挂载到容器的 Pod 里,之后通过 Containerd 启动 Pod;
-
启动完成后,Kubelet 会把 Pod 的状态更新回 API Server;
-
RKS watch 到 Pod 状态变化后,同步更新内存中的 Container 状态,之后等待 AM 心跳时同步 Container 最新状态;
持久化服务
YARN 架构是通过 ZKRMStateStore 将元数据信息持久化到 ZooKeeper,而 Yodel 架构,我们自己实现了一个 KVStateStore 存储元数据到 API Server,存储的元数据包括 MetaData,Queue,Application,Appattempt 和 Pod。现在线上的一个 API Server 可以支持存储 300 queue,2w 个 application,10w 个 app attempt,以及支持 30W 离线 Pod 同时运行。
平滑迁移
字节内每天运行着百万量级的任务,如何平滑地把作业从 YARN 架构迁移到 Yodel 架构是一个很大的挑战,整体上我们是通过 ResLake 来完成的,首先介绍几个关键组件:
ResLake 在 YARN 集群和 Yodel 集群上有同名的队列,如上图中的 root.queueA 和 root.queueB,这两个集群上的队列有着相同的元数据信息。 AutoMigration 服务会不断地从 YARN 搬迁节点到 Yodel 集群,搬迁信息会同步给 Quota Platform,Quota Platform 会进一步将队列 Quota 信息同步给 Reslake。作业托管平台提交作业到 ResLake 时,ResLake 会根据 YARN/Yodel 上队列的 Quota 信息,决定作业是提交到 YARN 集群还是 Yodel 集群。随着机器不断地往 Yodel 搬迁,最终作业也平滑迁移到了 Yodel 集群上。
重要优化
在 Yodel 架构升级上线过程中,也遇到了很多问题,我们也做了非常多的优化,主要包括性能优化和运行优化。
性能优化
运行优化
上线收益
Yodel 架构已经在字节内部上线,上线后带来了如下收益:
未来规划
了解更多字节跳动云原生计算相关实践,欢迎申请试用或技术交流,同时欢迎加入飞书【云原生计算技术交流群】~
👇 云原生计算技术交流群 👇
展开阅读全文