企业应用的需求正变得越来越高。智能体式AI进一步加剧了对海量企业数据的需求,带来了针对日益庞大数据集的频繁、复杂查询。

要满足这种需求,就需要在不成比例增加成本的前提下提升数据吞吐量。NVIDIA cuDF通过利用GPU的大规模并行能力和高带宽内存来处理数据分析,从而应对这一挑战。其中,用于Apache Spark的NVIDIA cuDF插件将这种加速能力带入Apache Spark——这个大数据处理与分析领域的行业领先平台,从而在主要工作负载中实现更优的总拥有成本表现。

用户自定义函数(UDF)长期以来都是加速查询引擎的难题,由于其不透明的特性,会带来运行时开销。虽然UDF通常可以用性能更优的代码替代,但重写UDF一直是一项费力的工作,需要仔细验证。

本文介绍如何使用智能体在数分钟内将UDF重写为GPU加速的等效版本,在Apache Spark作业中实现22倍以上的加速。我们将介绍用于Apache Spark的cuDF技能集,这是一套能够快速突破UDF瓶颈的技能,涵盖从测试、基准测试到集成的端到端开发流程。

UDF挑战

cuDF实现无缝GPU加速的部分原因在于Apache Spark的声明式编程接口。SQL/数据帧抽象之所以强大,是因为它们将查询应得的结果与系统应执行的方式分离开来。这使得cuDF插件能够利用GPU的大规模SIMD能力,透明地并行化按行操作,而无需改动用户代码。

然而,Apache Spark也支持UDF:用于扩展内置功能的自定义程序。虽然UDF在实现定制业务逻辑方面很有用,但它们破坏了声明式抽象——它们包含系统无法推理或以通用方式并行化的任意用户代码。在执行过程中,GPU加速器必须将数据从列式格式转换为行式格式,并回退到CPU逐行执行UDF。

因此,在一个本应被加速的查询中,UDF存在以下缺点:

由于回退机制,UDF会产生数据往返传输的开销。

如果UDF是用GPU加速的原语编写的,本可以获得的计算加速将被放弃。

加速UDF

通过小而有针对性的代码改动,许多UDF可以借助正确的原语重写为可被GPU加速的形式。重写UDF可以消除与加速器回退相关的开销,并能带来超过20倍的加速。

我们概述了三种重写UDF的方法。

为了使这些方法更具体,我们以一个将摄氏温度转换为华氏温度的简单Scala UDF为例:

```

final class ToFahrenheit extends Function1[java.lang.Double, java.lang.Double] with Serializable { override def apply(celsius: java.lang.Double): java.lang.Double = { if (celsius == null) null else celsius * 9.0 / 5.0 + 32.0 } } spark.udf.register("to_fahrenheit", new ToFahrenheit) spark.sql(""" SELECT *, to_fahrenheit(celsius) AS fahrenheit FROM temperatures """)

```

用SQL重写UDF

对于简单的UDF,最直接的解决方案是用等效的Spark SQL表达式替换该UDF:

```

spark.sql(""" SELECT *, celsius * 9.0 / 5.0 + 32.0 AS fahrenheit FROM temperatures """)

```

这样一来,该函数在Spark的表达式树中变得可见。在查询规划期间,cuDF插件会将这些表达式替换为对应的GPU实现,使数据和执行过程完全保留在GPU上。

用cuDF重写UDF

当SQL原语不足或不适用时,可以改用RapidsUDF接口——这是cuDF插件提供的一种契约——让UDF直接在GPU列上操作。该契约要求实现一个方法:evaluateColumnar:

```

import ai.rapids.cudf.{ColumnVector, Scalar} import com.nvidia.spark.RapidsUDF import scala.util.Using final class ToFahrenheit extends Function1[java.lang.Double, java.lang.Double] with Serializable with RapidsUDF { override def apply(celsius: java.lang.Double): java.lang.Double = { if (celsius == null) null else celsius * 9.0 / 5.0 + 32.0 } override def evaluateColumnar( numRows: Int, args: ColumnVector*): ColumnVector = { Using.Manager { use => val scale = use(Scalar.fromDouble(9.0 / 5.0)) val offset = use(Scalar.fromDouble(32.0)) val scaled = use(args.head.mul(scale)) scaled.add(offset) }.get } }

```

cuDF插件会识别RapidsUDF接口的实例,并将一个驻留在GPU上的ColumnVector传递给evaluateColumnar函数。该函数随后通过组合cuDF Java API中的操作来并行处理这一列数据。这种方法为更复杂的处理提供了更丰富的API。

用CUDA重写UDF

对于那些无法通过现有cuDF操作高效组合实现的高度复杂逻辑,RapidsUDF可以通过Java本地接口(JNI)调用自定义的CUDA内核。为简洁起见,我们省略了相关代码,但CUDA转换的示例可以在cuDF面向Spark UDF的示例中找到。

借助AI智能体高效重写

尽管性能收益显著,但UDF重写往往需要大量工程投入。它要求仔细选择API、进行语义验证并测量性能,而列式API对于缺乏向量化编程经验的开发者而言可能较为陌生。

幸运的是,这其中的大部分工作非常适合交由编程智能体完成。在适当的防护机制下,智能体可以搜索不熟悉的API、实现候选重写方案并快速迭代,同时通过可执行测试和性能测量来判断每次改动是否可接受。

可用技能

面向Apache Spark的cuDF技能集将重写过程拆解为四个专注的反馈循环。每项技能都明确规定了需要完成的工作以及进入下一阶段所需的证据:

图2:四项技能引导智能体完成测试、转换、基准测试和优化,并在每个阶段采用验证驱动的反馈循环

脚手架搭建与设计

可靠的智能体执行始于可靠的开发环境。这些技能提供了完整的项目模板,其中包含端到端开发所需的cuDF和Spark专用脚手架。这包括测试与基准测试框架、用于输出验证的编码例程以及构建配置。通过将这些知识编码到代码中,智能体可以专注于UDF本身,而无需反复重建专用基础设施。

这些技能还提供了使用cuDF进行GPU编程的最佳实践,包括内存管理和配置方面的内容,作为建议性的技巧参考。为了充分发挥前沿模型的能力,智能体仍可自由地根据上下文探索不同的实现方式,并基于实测的正确性和性能选择最合适的方案。

性能结果

一家大型消费科技公司利用这一工作流程,将生产数据管道中使用的30多个UDF转换为GPU加速实现。重写后的版本保留了原始CPU UDF的行为,同时消除了本应被GPU加速的工作负载中代价高昂的回退操作。举例来说,以下基准测试展示了某个工作负载中一个UDF重写前后的性能对比。

这个特定的UDF影响了超过3000个作业,在该作业中,当其以支持cuDF的RapidsUDF形式实现后,获得了22倍的加速。借助智能体的帮助,这类性能提升变得更容易实现,使开发者能够在数小时内(而不是数天或数周)完成重写迭代,同时不损害正确性。

开始使用

将UDF转换为GPU实现可以带来显著的加速,并有助于降低GPU加速管道的整体成本。借助智能体技能,重写过程可以变得既简单又可靠。

要开始使用,可以在GitHub上安装面向Apache Spark的cuDF技能集,可以直接安装,也可以使用npx技能安装工具:

```

npx skills add NVIDIA/cudf-spark --skill ‘*’

```

如需更深入了解该工作流程以及构建过程中的实践经验,可参阅Data + AI Summit会议内容:《用AI智能体编程为你的Spark UDF注入GPU加速能力》。

如需了解更多关于Apache Spark的GPU加速信息,请参阅面向Apache Spark的cuDF插件入门指南,以在你的Spark管道中解锁更佳的性能和总拥有成本表现。访问我们的网页,了解更多关于NVIDIA cuDF(GPU加速的结构化数据处理)的信息,或者阅读相关文档,了解更多关于用于Apache Spark的NVIDIA cuDF插件的信息。

Q&A

Q1:什么是用于Apache Spark的cuDF技能集?

A:这是NVIDIA推出的一套智能体技能,用于快速将Apache Spark中的用户自定义函数(UDF)重写为GPU加速的等效版本,涵盖测试、转换、基准测试和优化等端到端开发环节。

Q2:使用cuDF技能集重写UDF能带来多大的性能提升?

A:根据实际案例,一个影响超过3000个作业的UDF在重写为支持cuDF的RapidsUDF后,实现了22倍的速度提升,大幅降低了GPU加速管道的整体成本。

Q3:如何开始使用cuDF技能集?

A:可以在GitHub上直接安装该技能集,也可以通过npx技能安装工具执行命令npx skills add NVIDIA/cudf-spark --skill '*' 进行安装。

NVIDIA