Spark原生GPU调度的前世今生

背景与实现概述

众所周知,GPU作为通用的加速硬件,被越来越广泛的用于图形图像处理、深度学习、高性能计算等领域, 效果显著。

ML/DL领域,Tensorflow, PyTorch 等深度学习框架大行其道,而 Spark 提供的 GraphX 和 MlLib 可以做一些机器学习的东西,但是在深度学习的战场里没有什么优势,最大的问题就在于硬件加速上,3.0 以前的社区版 Spark 没有调度 GPU 的方法。

训练模型除了本身的大规模的并行密集计算,从数据到模型,必须有数据处理的过程,这也是 Spark 的强项,因为你不太可能用 pandas 简单清洗汇总你的训练数据,而且做AI业务的企业往往已经部署有一套大数据平台环境。

这既是机遇也是挑战!

社区SPIP

Accelerator-aware task scheduling for Spark:SPARK-24615

Design sketch:SPARK-27005

SPIP:Spark Project Improvement Proposal,Spark项目改进方案

2018年,Hadoop3.1 YARN已经支持GPU调度。

Apache Spark支持的资源管理器 YARN 和 Kubernetes 已经支持了 GPU。为了让 Spark 也支持 GPU,在技术层面上需要做出两个主要改变:

  • cluster manager 层面上,需要升级 cluster managers 来支持 GPU。并且给用户提供相关 API,使得用户可以控制 GPU 资源的使用和分配。
  • 在 Spark 内部,需要在 scheduler 层面做出修改,使得 scheduler 可以在用户 task 请求中识别 GPU 的需求,然后根据 executor 上的 GPU 供给来完成分配。

因为让 Apache Spark 支持 GPU 是一个比较大的特性,所以项目分为了几个阶段。在 Apache Spark 3.0 版本,将支持在 standalone、 YARN 以及 Kubernetes 资源管理器下支持 GPU,并且对现有正常的作业基本没影响。对于 TPU 的支持、Mesos 资源管理器中 GPU 的支持、以及 Windows 平台的 GPU 支持将不是这个版本的目标。而且对于一张 GPU 卡内的细粒度调度也不会在这个版本支持(指spark3.0)。

2020年6月,Spark3.0.0发布开始支持GPU调度。

Spark Scheduling

在这个层面,我们得允许从 RDD/PandasUDF API 中指定资源请求,这些请求应该在 DAGScheduler 中汇总。TaskSetManager 管理每个 Stage 挂起(pending)的任务,对于那些有 GPU 请求的任务,我们需要处理;对于那些不需要 GPU 的作业,其调度行为和效率应该和之前保持一致。

目前,CPUS_PER_TASK(spark.task.cpus)是一个 int 类型的全局配置,用于指定每个 task 应分配的 cores。为了支持 GPU 的配置,引入了 spark.task.gpus 参数用于指定每个 task 需要申请的 GPU 数。如果用户没有指定 spark.task.cpus 或 spark.task.gpus,那么 Spark 程序将使用默认的值;因为需要向后兼容,所以如果用户没指定spark.task.cpusspark.task.gpus,这两个参数的默认值分别为 1 和 空。

对于 ExecutorBackend ,需要使得它可以识别和管理 GPU ,并且把这些信息同步(比如修改现有的 RegisterExecutor 类)到 SchedulerBackend,然后 SchedulerBackend 可以根据这些 GPU 信息,为那些需要 GPU 资源的 task 进行资源分配。

Resource Manager

第一阶段将在 Standalone、YARN 以及 Kubernetes 上支持 GPU。Spark 需要在这三种资源管理上面做一些工作。

  • Standalone

Standalone 是 Spark 内置的资源管理模式,但是之前的 Standalone 部署模式并不能支持 GPU 等资源。为了能识别 GPU 信息,一种可行的方法是在配置文件里面对 GPU 资源进行配置, Worker 通过读取这些配置信息,并在内存结构里面维护 GPU 和 CPU 等可用资源等信息。同时,在 Master 上通过 allocateWorkerResourceToExecutors 方法对 Executors 申请的资源(包括 GPU)进行分配。

  • YARN

为了能够在 YARN 上支持 GPU,我们需要使用 YARN 3.1.2+ 版本;同时我们需要在 YARN 集群上做出相关配置,使得 YARN 启动了对 GPU 资源的支持,关于如何在 YARN 上配置 GPU 资源,请参见这里

当为 Executors 申请 YARN 容器时,Spark 需要在 YARN 容器请求中将 executor 所需的 GPU 数量映射到 yarn.io/gpu 资源中。YARN 具有 GPU 隔离机制,所以无论是否使用 Docker 容器, 对未分配给 YARN 容器的 GPU 资源的使用将会被阻止。

需要注意的是,截至目前 YARN 仅支持 Nvidia GPU

  • Kubernetes

从 Kubernetes 1.8 版本开始,Kubernetes 使用设备插件模型(device plugin model)来支持 GPU、高性能NIC,FPGA 等设备。目前 Kubernetes 支持 Nvidia 、AMD 和 Intel 的 GPU 设备。在 Spark + k8s 里面为 task 指定 GPU 的数量和在 Standalone 或 YARN 模式里面一样。也是支持 spark.task.gpusspark.executor.gpus 的全局配置,也支持在 RDD stage 中为每个 task 设置。

功能概述

GPU 和其他加速器已广泛用于加速特殊工作负载,例如深度学习和信号处理。Spark 现在支持请求和调度通用资源,例如 GPU。

Spark 将使用指定的配置首先从集群管理器请求具有相应资源的容器。一旦获得容器,Spark 就会在该容器中启动一个 Executor,它将发现容器拥有哪些资源以及与每个资源关联的地址。Executor 将向 Driver 注册并报告该 Executor 可用的资源。然后 Spark 调度器可以将任务调度到每个 Executor 并根据用户指定的资源需求分配特定的资源地址。

注意:它目前不适用于 Mesos 或本地模式。

阶段级调度(Stage Level Scheduling)

阶段级别调度功能(SPARK-27495)允许用户在阶段级别指定任务和执行器资源需求。这允许不同阶段与具有不同资源的执行程序一起运行。一个典型的例子是一个 ETL 阶段,执行器只使用 CPU,下一个阶段是需要 GPU 的 ML 阶段。阶段级调度允许用户在 ML 阶段运行时请求具有 GPU 的不同执行器,而不必在应用程序开始时获取具有 GPU 的执行器,并且在 ETL 阶段运行时它们处于空闲状态。

这仅适用于 Scala、Java 和 Python 中的 RDD API。当启用动态分配时,它在 YARN 和 Kubernetes 上可用。

该功能在Spark3.0.0版本还没有实现,在Spark3.1版本才有。

YARN上资源分配与配置

YARN 3.1.0 中添加了 YARN 上的GPU资源调度。理想情况下,资源是隔离设置的,以便执行器只能看到分配给它的资源。如果您没有启用隔离,则用户负责创建一个发现脚本,以确保资源不会在执行程序之间共享。

YARN 目前支持任何用户定义的资源类型,但内置了 GPU ( yarn.io/gpu) 和 FPGA ( yarn.io/fpga) 类型。因此,如果您正在使用这些资源中的任何一个,Spark 可以将对 spark 资源的请求转换为 YARN 资源。

对GPU和FPGA仅配置spark.{driver/executor}.resource. 否则配置YARN (spark.yarn.{driver/executor}.resource.) 和 Spark (spark.{driver/executor}.resource.)

例如:每个Executor请求2个GPUs,用户指定spark.executor.resource.gpu.amount=2,Spark会自行处理YARN上的yarn.io/gpu资源。如果是其他自定义资源,如acceX,则需要同时写spark.yarn.executor.resource.acceX.amount=2 and spark.executor.resource.acceX.amount=2.

YARN 不会告诉 Spark 分配给每个容器的资源地址。出于这个原因,用户必须指定一个发现脚本,该脚本在启动时由executor运行,以发现该executor可用的资源。可以在 examples/src/main/scripts/getGpusResources.sh中找到示例脚本。

  • 阶段级调度

启用动态分配(dynamic allocation)时,YARN 支持阶段级调度

测试用例

一个简单的资源spark-shell GPU配置启动:

./bin/spark-shell --master yarn --executor-cores 2 \
--conf spark.driver.resource.gpu.amount=1 \
--conf spark.driver.resource.gpu.discoveryScript=/opt/spark/getGpuResources.sh \
--conf spark.executor.resource.gpu.amount=2 \
--conf spark.executor.resource.gpu.discoveryScript=./getGpuResources.sh \
--conf spark.task.resource.gpu.amount=1 \
--files examples/src/main/scripts/getGpusResources.sh

对于这种配置,我们期望在 Executor 上一次运行不超过两个任务,因为每个任务将使用一个 GPU,并且每个 Executor 最多有两个 GPU。

  • GPU分配API
// Task API
val context = TaskContext.get()
val resources = context.resources()
val assignedGpuAddrs = resources("gpu").addresses
// Pass assignedGpuAddrs into TensorFlow or other AI code

// Driver API
scala> sc.resources("gpu").addresses
Array[String] = Array(0)
  • 加速效果

criteo是非常经典的点击率预估比赛。训练集4千万行,特征连续型的有13个,类别型的26个,没有提供特征名称,样本按时间排序。测试集6百万行。

社区发展路线

Spark 2时代,正如我之前提到的,传统上在与机器学习相关的管道中,数据准备,在一个 CPU 集群上,由 Spark 编排,这必然会被序列化到共享存储,然后是一个单独的GPU集群将实际加载序列化数据备份并使用它进行训练,如 Tensorflow。

有了 Spark 3,我们终于有了一个统一的架构。我们有一个单一的管道,具备阶段级调度,我们实际上可以将它作为一个应用程序进行调度,我们可以进行数据摄取、准备和模型训练,所有这些都由 Spark 编排,单一平台,为 AI 而生。

Spark 3 with Project Hydrogen

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容