浅谈Spark之NativeSQL引擎

1,959 阅读5分钟

技术背景

Spark是大数据计算领域的标杆产品,据统计在使用Spark的业务中又有高达80%的场景使用Spark SQL实现。

Spark SQL多年来的性能优化集中在Optimizer和Runtime两个领域。前者的目的是为了获得最优的执行计划,后者的目的是针对既定的计划尽可能执行的更快。优化器(Optimizer)是更加通用的、跟实现无关的优化。Runtime的优化工作基本聚焦在解决当时的硬件瓶颈。提升CPU性能的两个主流技术是向量化技术和代码生成(CodeGen)技术,其中Spark跟进的是CodeGen。

image.png 我们在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

架构

image.png 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带来更好的性能。

概念详解

  1. Native指的是什么?本地是什么?

    “本地”是Native的翻译(也有翻译为“原生”),可以理解为C或C++实现。

    看过Java的Object类源码的会比较熟悉,其中有好多方法都带有native关键字,简单地讲,一个Native Method就是一个由java调用非java代码的接口,该方法是一个原生态方法,用其他语言(如C和C++)实现。

  2. 对SparkSQL的支持程度怎么样?

    项目称支持了TPC-HTPC-DS的大多数关键算子,如下表:

    No.ExecutorNotesBOOLEANBYTESHORTINTLONGFLOATDOUBLESTRINGDECIMALDATE
    1CoalesceExecyyyyyyyyyy
    2CollectLimitExecusing row version
    3ExpandExecyyyyyyyyyy
    4FileSourceScanExecyyyyyyyyyy
    5FilterExecyyyyyyyyyy
    6GenerateExecusing row version
    7GlobalLimitExecusing row version
    8LocalLimitExec
    9ProjectExecyyyyyyyyyy
    10RangeExecusing row version
    11SortExecyyyyyyyyyy
    12TakeOrderedAndPorjectExecusing row version
    13UnionExecyyyyyyyyyy
    14CustomShuffleReaderExecyyyyyyyyyy
    15HashAggregateExecyyyyyyyyyy
    16SortAggregateExecyyyyyyyyyy
    17DataWritingCommandExecusing row version
    18BatchScanExecyyyyyyyyyy
    19BroadcastExchangeExecyyyyyyyyyy
    20ShuffleExchangeExecyyyyyyyyyy
    21BroadcastHashJoinExecyyyyyyyyyy
    22BroadcastNestedLoopJoinExecusing row version
    23CartesianProductExecusing row version
    24ShuffledHashJoinExecyyyyyyyyyy
    25SortMergeJoinExecyyyyyyyyyy
    26ArrowEvalPythonExecusing row version
    27WindowINPandasExecusing row version
    28WindowExecyyyyyyyyyy

    还有更多的SQL函数不一一列出了。如果不支持某算子,会回退到原生Spark执行。

  1. 哪些CPU才支持(需要SIMD)?

    目前广泛使用的Intel(R) Xeon系列6130、6140、5130的CPU都支持SIMD。在Linux中使用lscpu查询支持指令集,flags包含avx2avx512等就行。

  2. 数据源是text格式能否适用?性能怎么样?

    可以用,File Format只会影响最一开始FileScan这个Stage的支持(性能略下降),当数据读到内存后统一会转换到Arrow的格式放进到memory中暂存并做Native SQL的计算。相比parquet格式性能要低一些。

  3. 具体的性能提升怎么样?

    项目官网展示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任务得到不同程度提速!

    后续将会详细说明测试与使用的情况。