技术背景
Spark是大数据计算领域的标杆产品,据统计在使用Spark的业务中又有高达80%的场景使用Spark SQL实现。
Spark SQL多年来的性能优化集中在Optimizer和Runtime两个领域。前者的目的是为了获得最优的执行计划,后者的目的是针对既定的计划尽可能执行的更快。优化器(Optimizer)是更加通用的、跟实现无关的优化。Runtime的优化工作基本聚焦在解决当时的硬件瓶颈。提升CPU性能的两个主流技术是向量化技术和代码生成(CodeGen)技术,其中Spark跟进的是CodeGen。
我们在Spark任务的DAG图中很容易看到
WSCG(全阶段代码生成)的身影。CodeGen技术从算子融合角度解决虚函数开销和中间数据物化问题:简单来说,CodeGen框架通过生成与手写代码语义相同且形式类似的Java代码,紧接着用对应的工具链编译生成的代码,最后用编译后的class(Java)执行,从而把解释执行转变成了编译执行。
今天要说的NativeSQL相当于是spark sql的新的执行内核,在典型的场景下能够提升Spark任务30%~80%的性能,而这一切都无需额外购买或升级硬件设施。
项目动机
针对当前Spark SQL引擎存在的一些问题:
- Row-based处理、不能利用SIMD技术(Intel AVX)
- Java GC消耗难以把控
- JIT代码质量依赖于JVM,难以调优
- 与其他native的库集成很困难
补充:
JIT:VM执行的动态JIT (just-in-time)编译
AVX:Intel Advanced Vector Extensions (Intel AVX)、单指令多数据流指令集
NativeSQL的目标:
- 将关键算子改为高效的native代码,加速大多数SQL分析
- 使得Spark更容易集成其他加速器(FPGA等)
简介与架构
定义
一个用于Spark SQL的本地引擎,具有矢量SIMD优化功能。
NativeSQL开源项目名为Gazelle Plugin。
架构
Spark SQL在行式结构化数据中效果非常好。它使用
WholeStageCodeGen来提高Java JIT代码的性能。然而,Java JIT通常不能很好地发挥最新SIMD指令的强大能力——特别是在复杂的查询下。Apache Arrow提供了CPU缓存友好的列式内存布局,它的SIMD优化内核和基于LLVM的SQL引擎Gandiva也非常高效。
Gazelle插件在Apache Arrow的基础上用SIMD友好的列式数据处理重新实现了Spark SQL执行层,并利用Arrow的CPU缓存友好的列式内存布局、SIMD优化的内核和基于LLVM的表达式引擎,为Spark SQL带来更好的性能。
概念详解
-
Native指的是什么?本地是什么?
“本地”是Native的翻译(也有翻译为“原生”),可以理解为C或C++实现。
看过Java的Object类源码的会比较熟悉,其中有好多方法都带有
native关键字,简单地讲,一个Native Method就是一个由java调用非java代码的接口,该方法是一个原生态方法,用其他语言(如C和C++)实现。 -
对SparkSQL的支持程度怎么样?
项目称支持了
TPC-H和TPC-DS的大多数关键算子,如下表:No. Executor Notes BOOLEAN BYTE SHORT INT LONG FLOAT DOUBLE STRING DECIMAL DATE 1 CoalesceExec y y y y y y y y y y 2 CollectLimitExec using row version 3 ExpandExec y y y y y y y y y y 4 FileSourceScanExec y y y y y y y y y y 5 FilterExec y y y y y y y y y y 6 GenerateExec using row version 7 GlobalLimitExec using row version 8 LocalLimitExec 9 ProjectExec y y y y y y y y y y 10 RangeExec using row version 11 SortExec y y y y y y y y y y 12 TakeOrderedAndPorjectExec using row version 13 UnionExec y y y y y y y y y y 14 CustomShuffleReaderExec y y y y y y y y y y 15 HashAggregateExec y y y y y y y y y y 16 SortAggregateExec y y y y y y y y y y 17 DataWritingCommandExec using row version 18 BatchScanExec y y y y y y y y y y 19 BroadcastExchangeExec y y y y y y y y y y 20 ShuffleExchangeExec y y y y y y y y y y 21 BroadcastHashJoinExec y y y y y y y y y y 22 BroadcastNestedLoopJoinExec using row version 23 CartesianProductExec using row version 24 ShuffledHashJoinExec y y y y y y y y y y 25 SortMergeJoinExec y y y y y y y y y y 26 ArrowEvalPythonExec using row version 27 WindowINPandasExec using row version 28 WindowExec y y y y y y y y y y 还有更多的SQL函数不一一列出了。如果不支持某算子,会回退到原生Spark执行。
-
哪些CPU才支持(需要SIMD)?
目前广泛使用的Intel(R) Xeon系列6130、6140、5130的CPU都支持SIMD。在Linux中使用
lscpu查询支持指令集,flags包含avx2、avx512等就行。 -
数据源是text格式能否适用?性能怎么样?
可以用,File Format只会影响最一开始FileScan这个Stage的支持(性能略下降),当数据读到内存后统一会转换到Arrow的格式放进到memory中暂存并做Native SQL的计算。相比parquet格式性能要低一些。
-
具体的性能提升怎么样?
项目官网展示NativeSQL性能(Gazelle)是Spark3的1.49倍。
the result shows a 1.49X performance speed up from OAP v1.0-Gazelle Plugin comparing to Vanilla SPARK 3.0.0
作者在一次实际测试中,基于TPC-H的基准测试验证了单条SQL性能提升最高93%,大部分耗时长的SQL任务得到不同程度提速!
后续将会详细说明测试与使用的情况。