字节跳动 YARN 云原生化演进实践|CommunityOverCode Asia 2023

技术

本文整理自火山引擎云原生计算研发工程师邵凯阳在 CommunityOverCode Asia 2023 中的《字节跳动云原生 YARN 实践》主题演讲。

字节跳动内部离线业务规模庞大,线上每天运行数十万节点、数百万任务,使用的资源达千万量级,内部由在线调度系统和离线调度系统分别负责在离线业务的调度管理。但随着业务规模的发展,这套系统也暴露了一些短板:运维负担繁重、资源利用率低、隔离能力差等。

基于此背景字节跳动提出基于云原生的 YARN 解决方案 —— Serverless YARN,其 100% 兼容 Hadoop YARN 协议, Hadoop 生态下的大数据作业无需修改即可透明迁移到云原生系统上,在/离线资源间可以高效灵活转换、分时复用,集群整体资源利用率得到显著提升。

0 1

业务背景

字节跳动(以下简称字节)内部离线业务具有庞大的规模,线上每天有数十万节点运行,每天的任务数达到百万量级,每天使用的资源量达到千万核量级。在如此庞大的计算规模下,为了能够高效地处理任务,提高资源流转效率,调度系统发挥了非常重要的作用。

picture.image

如上图所示,我们可以清楚地看到,字节内部调度架构分为两大块 —— 离线调度系统在线调度系统 ,离线调度系统主要负责离线资源管理和离线任务调度,在线调度系统主要负责在线资源管理和在线任务调度。

  • 离线调度系统基于 YARN 实现,主要包括 Resource Manager(RM) 和 Node Manager(NM) 两个组件,分别负责资源调度和容器运行时管理。字节内部在 YARN 的基础上进行了很多功能丰富和优化工作,针对不同场景实现了不同的调度器,例如:Batch Scheduler,Gang Scheduler 等;
  • 在线调度系统基于 Kubernetes 生态,进行了很多优化,支持字节内部多样化的在线服务。

为了提高字节内部整体的资源利用率,我们也进行了 混部技术的探索。 主要思路是在在线的节点上同时部署 Kubelet 和 NM 服务,当在线节点比较空闲时可以及时将空闲资源出让给离线业务使用,以此使得整个数据中心的资源利用率能够得到比较大的提升。

但随着公司内业务规模的持续发展,这一套系统也暴露出了一些短板:

  • 首先,在离线属于两套系统,一些重大活动场景需要通过运维方式进行在离线资源转换,运维负担繁重,转换周期长;

  • 其次,在离线是两套割裂的系统,资源池不统一使得整体资源利用率不高,Quota 平台、机器运维等都不能复用;

  • 大数据作业无法享受到云原生的各种好处,例如:强制的容器化能力、可定制的网络/存储能力、便捷的运维能力等。

综上所述,字节内部有三个核心诉求:

  • 重大活动场景(春节/双 11 等),在离线资源需要能够 高效、灵活 地相互转换;

  • 整个数据中心的利用率需要得到更全面、充分的提升,进一步 降本增效

  • 在离线 资源共池 ,Quota 管控、调度、运行、机器运维统一。

为了实现上述诉求,我们进行了一些思考和探索。其中一种解决方案是: 能不能让离线作业直接迁移到云原生系统? 即:大数据生态下的各个计算引擎(包括:Spark、Flink 等)进行深度改造去适配 Kubernetes。

在探索过程中发现这种方式有比较大的缺点,主要有以下三点:

  • 传统开源大数据引擎不是针对云原生设计,AM-Task 作业形态难以直接云原生部署,计算引擎侧需要做大量改造才能支持原先在 YARN 的各种特性;
  • 开源云原生系统不具备 YARN 的多租户资源管控能力、作业级调度策略、调度吞吐较低;
  • 生产环境的作业(百万级)非常多,如何从 YARN 平滑迁移到云原生系统也是个比较大的问题。

基于以上思考,我们提出了一种全新的解决方案 —— Serverless YARN其 100% 兼容 Hadoop YARN 协议, Hadoop 生态下的离线任务无需修改即可运行在云原生系统上。使得在离线资源可以高效灵活转换、分时复用,集群整体资源利用率得到充分提升。

02

解决方案

下面将从 Serverless YARN 整体架构、Remote Scheduler Service 服务、Remote Kubelete Service 服务、GRO Scheduler、平滑迁移等方面来详细介绍我们的解决方案。

Serverless YARN 整体架构

Serverless YARN 基于 YARN 实现,新增 ZK/ETCD State Store、Remote Scheduler Service、Remote Kubelet Service 服务。ZK/ETCD State Store 主要用于持久化存储、Remote Scheduler Service 维护资源请求并与 API Server 交互,将调度能力统一到 GRO Scheduler;Remote Kubelet Service 实现了 YARN NM 所有接口,对用户和作业透明的前提下,把 NM 的 Container 管理能力平滑下沉到 Kubelet。

picture.image

Serverless YARN 整体架构图

从上图可以清楚看到 Serverless YARN 的整体架构, 图中蓝色组件是进行了适配改造的组件,蓝色中标红的组件是新增组件,黄色组件是 Kubernetes 生态下的组件, 关于新增组件:

  • ZK/ETCD State Store :支持将集群元数据信息持久化到 ZK、 ETCD 等持久化存储,可以通过 API Server 方便地进行相关数据查询和更新;

  • Remote Scheduler Service :维护集群所有任务的资源请求,通过该服务将任务的资源请求转化为 Pod 写入 API Server,同时与 API Server 交互获取已调度的 Pod,最终将调度能力下沉到底层的 GRO Scheduler;

  • Remote Kubelet Service :实现了原来 YARN 中 NM 的所有接口,例如:启动容器、停止容器、获取容器状态的接口。通过这个服务容器启动从 NM 切换到 Kubelet,最终将容器运行时的管理下沉到底层的 Kubelet。

下面介绍在 Serverless YARN 架构下一个离线任务的提交和运行流程:

  1. 用户从开发机或任务托管平台向集群提交一个任务;

  2. 当任务经过校验后,Serverless YARN RM 会新建一个 App 对象并持久化至 API Server;

  3. Serverless YARN RM 创建 AM Pod 并写入 API Server,等待底层调度器调度;

  4. Serverless YARN RM 收到已经调度完成的 AM Pod 并进行相关转化操作;

  5. Serverless YARN RM 将相关启动信息丰富至 AM Pod 中并 Patch 至 API Server 由 Kubelet 拉起相关进程;

  6. AM 启动成功后,随心跳主动向 Serverless YARN RM 申请资源;

  7. Serverless YARN RM 收到任务的资源请求后,通过 Remote Scheduler Service 服务将资源请求转化为 Pod 对象或 PodGroup 对象并写入到 API Server;

  8. 底层调度器 Watch 到相关对象后,按照一定策略进行调度,同时 Serverless YARN RM 也会及时地 Watch 到已经调度的 Pod;

  9. Serverless YARN RM 会将已经调度的 Pod 转化为 Container,随心跳返回给对应的 AM;

  10. AM 收到已经调度的 Container 后,会再跟 Serverless YARN RM 进行交互,来启动对应的容器;

  11. Serverless YARN RM 收到容器启动请求后,通过 Remote Kubelet Service 服务将容器启动所需要的信息丰富到 Pod 对象里并 Patch 到 API Server。Kubelet Watch 到待启动的 Pod 后,会进行这个 Pod 的启动。

Remote Scheduler Service

picture.image

Remote Scheduler Service 架构图

下面来介绍调度模块比较重要的一个服务 —— Remote Scheduler Service 服务。由上图可以看到, Remote Scheduler Service 服务主要分为三大部分:

  • 最上层是 Quota Manager 负责进行 Quota 管理: Quota Manager 部分在 YARN 基础上进行了增强。在 YARN 中有队列的概念,但队列只支持一种资源类型。在 Serverless YARN 中对此进行了扩展,一个队列可以同时支持两种类型的资源 —— Guaranteed Resource 和 Best-effort Resource。单队列支持两种资源类型后可以显著简化用户的队列管理成本,对用户使用更友好。
  • Guaranteed Resource :稳定资源,使用 Guaranteed Resource 的容器一般情况下不会被抢占也不会被驱逐;
  • Best-effort Resource :混部资源, 是在线节点出让的暂时空闲不用的资源,资源会随着节点负载情况动态波动,使用 Best-effort Resource 的容器可能会被抢占或驱逐。
  • 中间层是 Allocate Service 负责进行请求转换和状态维护: 主要包括四个子服务,Convert Reqeust To Pod Service 负责将任务的资源请求转化为 Pod 对象并写入 API Server;Convert Pod To Container Service 负责将已经调度的 Pod 转化为 Container 并返回给 AM;Update Pod Status Service 负责及时更新 Pod 状态并持久化至 API Server ;Delete Pod Service 负责在容器或任务结束时,及时删除 API Server 中的相关对象。

  • 最下层是 Remote Scheduler 负责进行调度和关键信息持久化。

Remote Kubelet Service

picture.image

Remote Kubelet Service 架构图

接下来介绍 Remote Kubelet Service 服务 Remote Kubelet Service 部署在 Serverless YARN RM 内部,实现了 YARN NM 的所有接口,把 NM 的 Container 管理能力平滑下沉到 Kubelet 它主要由两部分组成:

  • Patch Pod Service : 主要负责收到 AM 拉起请求后,将容器启动所需的信息丰富到 Pod 对象中,这些信息包括:容器的 ENV 、 HDFS 自研列表、启动命令等;
  • Pod Status Update Service : 该服务会及时从 API Server Watch Pod 的最新状态,并将状态返回给对应 AM。

此外,为了补齐 NM 上的运行体验,底层以 daemonset 方式部署了一些其他服务。这些 daemonset 补齐了 NM 的能力,使得离线作业只需要升级 hadoop 依赖,不用做太多改动,就能让容器运行在 Kubelet 上。这些服务包括:

  • LocalizationService: 用于下载 Pod 所需的 HDFS 资源;
  • Log Serving: 用于方便用户查看 Pod 日志;
  • Shuffle Service: 主要有 Spark Shuffle Service 及 MR Shuffle Service,这些 Shuffle Service 是从 NM 的进程解耦出来的,单独部署用于提供计算框架的 Shuffle 服务;
  • Metrics Collector: 用于收集离线 Pod 运行时的各维度监控信息;
  • Webshell: 方便用户通过 Web 端进入到容器的 Shell,方便排查问题。

下面看一个容器是怎么运行在 Kubelet 上的:

  1. 改造了 NM Client SDK,使 AM 调用 startContainer 时能直连 Remote Kubelet Service;

  2. Remote Kubelet Service 收到启动请求后,会把 containerLaunch 上下文等信息写入到 Pod 并 Patch 到 API Server;

  3. Kubelet Watch 到离线 Pod 后,会通过本机的 LocalizationService 下载 Pod 对应的 HDFS 资源;

  4. 下载完成后, Kubelet 通过 Containerd 把对应的 HDFS 资源挂载到容器的 Pod 里,之后通过 Containerd 启动 Pod;

  5. 启动完成后,Kubelet 会把 Pod 的状态更新回 API Server;

  6. Remote Kubelet Service watch 到 Pod 状态变化后,同步更新内存中的 Container 状态,之后等待 AM 心跳时同步 Container 最新状态。

GRO Scheduler

picture.image

GRO Scheduler 架构图

Kubenetes 默认的调度器 default scheduler 并不适合大数据场景的调度,因此实现了全新的 GRO Scheduler,其中有两个关键的组件 GRO Scheduler 和 GRO Agent:

  • GRO Scheduler:新增“队列”和“作业”概念,满足大数据场景的使用需求;支持多种排序策略,包括队列间排序、队列内任务排序、任务内 Pod 排序等;支持多种抢占策略,包括队列间抢占和队列内抢占;具有强大的 Pod 放置能力,支持丰富的调度约束,调度吞吐可达 2K/s;

  • GRO Agent:进行了多维资源单机隔离增强;支持在线 SLA 保障机制,当发现在线任务运行受影响时及时按照一定策略驱逐离线容器。

平滑迁移

picture.image

平滑迁移架构图

字节内每天运行着百万量级的任务,如何平滑地把作业从 YARN 架构迁移到 Serverless YARN 架构是一个很大的挑战,整体上我们是通过 ResLake 来完成的,首先介绍几个关键组件:

  • WorkFlow Hosting :作业托管平台,负责进行作业提交;
  • ResLake :是 RM Proxy,可以根据一定策略把作业路由到不同集群;
  • Quota Platform :用于同步队列的 Quota 信息;
  • AutoMigration :负责从 YARN 集群下线节点,搬迁到 Serverless YARN 集群上。

ResLake 在 YARN 集群和 Serverless YARN 集群上有同名的队列,如上图中的 root.queueA 和 root.queueB,这两个集群上的队列有着相同的元数据信息。AutoMigration 服务会不断地从 YARN 搬迁节点到 Serverless YARN 集群,搬迁信息会同步给 Quota Platform,Quota Platform 会进一步将队列 Quota 信息同步给 Reslake。作业托管平台提交作业到 ResLake 时,ResLake 会根据 YARN/Serverless YARN 上队列的 Quota 信息,决定作业是提交到 YARN 集群还是 Serverless YARN 集群。随着机器不断地往 Serverless YARN 搬迁,最终作业也平滑迁移到了 Serverless YARN 集群上。

03

生产实践

性能优化

在 Serverless YARN 架构升级上线过程中,也遇到了很多问题,我们也做了非常多的优化。

  • Recover 阶段异步恢复 Pod 状态降低切主时间( 秒级 ):起初为了确保切主后集群、队列和任务的各维度统计信息准确,采用同步方式恢复 Pod,但上线时发现恢复过程非常耗时。为此通过优化,在确保各维度信息统计准确的前提下异步恢复 Pod 状态,将切主时间缩短到秒级;
  • 异步多线程操作 Pod 以提高调度吞吐( ~2K/s ):通过异步多线程方式将已经调度 Pod 转化为 Container 后,调度吞吐得到显著提升,目前调度吞吐可以达到每秒 2000 个 Pod;
  • PodName 散列优化助力底层存储写延迟 降低为原来的1/100(百分之一): 因 API Server 底层采用基于 range 的 KV 存储,若 PodName 有序会频繁产生分区裂变,导致 API Server 的相关处理延迟显著增加。通过将 PodName 进行散列优化,将 Pod 打散存储在不同的分区中,底层存储写延迟下降 100 倍;
  • 与 API Server 交互增强,Java Fabric8 Kubernetes Client 优化:
  • 支持指数退让重试,增强 API Server 故障容错;
  • List 操作默认添加 ResourceVersion 参数,避免击穿到底层存储;
  • 将 Informer Resync 设置为 0,避免频繁内存拷贝造成 OOM。
  • AM 容器运行在单独资源池,独立优先级不可抢占:对于使用 BE 资源的容器有被抢占或驱逐的风险,而 AM 作为任务的 Master 一旦失败就会导致整个任务失败。为了避免此问题,将 AM 容器运行在单独的资源池,确保 AM 可以稳定运行避免任务失败;

  • 支持镜像本地化约束,平均拉起速度提升约 1000 倍:一些离线任务的镜像比较大,在容器启动时拉取镜像会花费较多时间,进而导致启动时间变长。为了解决该问题,支持了镜像本地化约束,让容器可以尽量调度到有镜像的节点,该功能上线后容器平均拉起速度提升 1000 倍;

  • 支持双栈节点和 v6 only 节点在单集群混跑:通过将双栈节点和 v6 only 节点混跑在同一个集群中显著降低了运维成本,同时也有利于资源利用率提升;

  • Shuffle 数据写远程,避免打爆本地磁盘:shuffle 数据通常较大很容易将本地磁盘打满,将 shuffle 数据写远程后,可以避免因本地磁盘打满而导致任务运行异常;

  • 大量引入 SSD 和 Nvme 磁盘,加速作业运行。

上线收益

Serverless YARN 架构已经在字节内部上线,上线后带来了如下收益:

  • 高效资源切换 :实现了 2022 元旦/春节 约 50 万核离线资源 分钟级 出让,显著提高了在离线资源转化效率,为重大活动场景下的资源切换提供了坚实的技术支撑;

  • 利用率提升 :NM 和周边单机组件下线,带来单机 2% 利用率提升;

  • 在离线统一 :在离线资源 全量共池 ,Quota 管控、调度、运行、机器运维统一;

  • 运维效率提升 :RM、Bigdata Plugin 通过容器化方式部署,极大提高了运维效率。

视频链接:

https://www.bilibili.com/video/BV1MB4y1Z7EM/?spm\_id\_from=333.999.0.0&vd\_source=c09f0713b2507369924e94f4fec6c133

点击底部 「阅读原文」 直达演讲视频

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论