随着计算技术的发展,软件逻辑层面的优化逐步到了一个平台期,因而各个引擎转向压榨底层硬件的方向发展,一个典型的例子就是以 Databricks Photon 为代表的 native 计算引擎。这些计算引擎充分利用 CPU 的计算优势,包括 SIMD 加速、流水线计算、CPU 高效缓存等。
与充分利用 CPU 的特性不同,on GPU 的计算采取了另一个思路。GPU 的特点是计算核数非常多,因而特别适合大量相同计算逻辑的计算子单元并行。对于数仓这种一次性按照同一个逻辑处理大批行的场景,GPU 非常适合。
基于此,Nvidia 推出 Rapids 项目。其中的 Spark Rapids 子项目使用 GPU 为 Spark 做算子加速。根据 Nvidia 的测试,基于 GPU 的加速可以取得平均数倍的性能提升,而成本节省可以达到原来的 30%~80%(依赖于不同硬件测试环境)。
火山引擎 E-MapReduce(EMR)提供了 GPU 机型,同时支持了 Spark Rapids。您可以在开通集群的时候选择该机型,同时做一下简单的配置即可使用 Spark Rapids。
Spark Rapids 支持了大部分 DQL 算子,但并没有完全支持。当遇到不支持的算子时,Spark Rapids 会回退到原生算子。
Spark Rapids 比较适合高散列度的 join、aggregation、window、sort,以及 udf 包含 cuda 计算、编码计算等场景,不太适合用于小数据量、重 io(包括 shuffle)、GPU 卡内存比较小,以及 udf 包含大量逻辑计算(与 cpu 频繁交互)的场景。
Spark Rapids 算子与原生算子之间存在一定程度的兼容性问题,比如浮点数的计算等。详细信息可参考 Spark Rapids 官方文档。
目前 EMR 不支持除 T4 与 V100 之外的其他机型(不支持 Multi-Instance GPU,Mig)。
对于不支持 Mig 的卡,无法做到一张物理卡虚拟多张卡,因此每个节点的 GPU 数就等同于物理卡数。这使得 Yarn 在调度的时候,一个节点只能有一个 container 拥有这张卡。所以,一张卡只能服务于一个 executor。但您依然可以启动一个大的 executor 通过配置多个 task(spark.rapids.sql.concurrentGpuTasks)来达到一个高并发度。
对于支持 Mig (比如 A100)的卡,一张卡可以虚拟出多张虚拟卡,不存在此问题。
已知以下的 GPU 集群风险,我们将在未来的版本逐步修复:
同时部署 GPU 节点组与非 GPU 节点组,可能造成 Spark on GPU 任务无法提交;
GPU 实例目前尚不支持提交包含 Delta Lake、Hudi、Iceberg 格式的 Spark on GPU 任务。
登录 EMR 控制台。
选择项目和地域信息后,在总览界面,单击创建集群按钮,进入集群创建流程界面。
在选择完基础的软件设置后,进入硬件配置 > 实例设置界面,单击 Core 节点组右侧操作列下的修改按钮,为 Core 节点组选择 GPU 计算型节点。
说明
由于 ECS 中 GPU 资源目前比较紧张, 若当前没有展现 GPU 计算型实例时,您可尝试切换网络可用区信息,或者可通过提工单形式,和 ECS 支持同学进行反馈。
单击确定按钮,完成 GPU 实例机型的选择。
后续剩余集群创建步骤,详见创建集群。
使用 Spark Rapids 仅需要对 Yarn 组件服务做出简单的配置即可。
针对不同的硬件卡,Yarn 组件需要做出不同的配置:
普通不支持 Multi-Instance(mig) 的卡,使用 Yarn 内置的 gpu plugin 即可;
针对 A100 这种能够硬件虚拟多张卡的高性能卡,需要使用 Nvidia 提供的支持 miggpu 插件。
resource-types.xml(或 yarn-site.xml)
<property> <name>yarn.resource-types</name> <value>yarn.io/gpu</value> </property>
yarn-site.xml
<property> <name>yarn.nodemanager.resource-plugins</name> <value>yarn.io/gpu</value> </property> <property> <name>yarn.nodemanager.resource-plugins.gpu.allowed-gpu-devices</name> <value>auto</value> </property>
配置好后重启 Yarn,即可看到 GPU 资源已经被支持:
可参考 Nvidia 给出的配置参考。
您可以和之前一样直接使用 Spark 即可,EMR 已经做好相关配置:
./bin/spark-shell
手动指定配置操作如下:
./bin/spark-shell \ --conf spark.plugins=com.nvidia.spark.SQLPlugin \ --conf spark.rapids.sql.concurrentGpuTasks=2
提交作业后,您可以通过 Spark UI 界面,便可以看到 GPU 资源已经被启用:
启动 spark-shell,执行如下语句,可以看到图中显示已经走了 GPU 的算子:
val seq= Seq(("1","xiaoming",15),("2","xiaohong",20),("3","xiaobi",10)) var rdd1 = sc.parallelize(seq) val df = rdd1.toDF("id","name","age") df.select("name","age").filter("age >10").show df.select("name","age").filter("age >10").explain //显示出执行计划