向量化执行模型已在现代数据库引擎被广泛应用,例如ClickHouse、TiDB、StarRocks等。为进一步提升计算性能,充分利用CPU计算能力,大数据计算引擎的不同厂商也针对向量化计算进行多样化探索。
Databricks 2022年推出商业化产品Photon,旨在增强Spark计算而写的Native C++ 向量化计算引擎。其执行层架构如图所示9,Photon向量化计算基于最底层的Task调度粒度处理 。扩展新的转换规则将原物理计划转为Photon物理计划,在Task级别实现向量化计算,提供高效的湖仓一体计算模式。Photon向量化执行引擎取代了已有的Spark执行模式(JVM & Codegen)。
Gluten项目由Intel和Kyligence于2021年合作共建,旨在通过开源社区推进Native Spark实现,为Spark扩展向量化执行(Vectorized Execution)能力,进一步提升引擎查询性能和CPU利用率。Gluten整体设计思想与 Photon相似,沿用Spark执行框架,基于新增GlutenPlugin 和 加载Session Extensions实现自定义扩展。
Gluten Plugin在向量化执行中处于“承上启下”位置,承上对接Spark物理计划,启下对接原生Native执行引擎。 Gluten Plugin组件如图所示包括[1]:
Spark Driver处理查询请求的基本流程如下图所示,(1).基于Spark Catalyst框架进行SQL解析和逻辑计划优化,(2).基于SparkPlanner进行物理计划优化,(3).优化后的物理计划SparkPlan
基于规则进行处理并转换成RDD对象。Spark底层执行基于火山模型实现,需要对每个算子进行迭代计算。
为提升执行效率,从 Spark 2.0 开始,社区开始引入全阶段代码生成(Whole-stage Code Generation)优化。基于CodeGen 将子计划树压缩为一段可执行代码,避免子计划树节点的逐个计算,大幅减少虚函数调用,显著提升查询性能。从 Spark 3.0 开始,社区支持自适应查询执行(Adaptive Query Execution, AQE) ,在DAG Stage执行过程中,基于上一个Stage的真实执行统计信息,重新生成更优的执行计划,动态优化下一个Stage的执行逻辑。
Gluten实现向量化计算的主要变更如下所示,在QueryExecution
执行前优化过程中,通过注入规则对物理计划进行扩展处理,转为Gluten物理计划,使用向量化执行模式替换已有的JVM + CodeGen的执行模式。在Task执行阶段,基于Gluten RDD,通过JNI调用Native引擎(默认Velox)实现向量化执行。
基于Gluten branch-1.1 分支,整体解析实现细节如下,主要包括四个模块: Spark、Gluten、Substrait和Velox,三个扩展流程: 规则注入、转换、执行。
preparations
维护处理规则,核心转换规则包括:
(1). EnsureRequirements: 核心逻辑在ensureDistributionAndOrdering
方法中,确保物理计划的数据分布(Distribution)与排序(Ordering)正确性,当数据分布和有序性无法满足当前节点的处理逻辑,则会添加Shuffle或排序操作;即添加Exchange节点或SortExec节点,其中,Exchange节点是实现数据并行化的重要算子。
(2). CollapseCodegenStages: 代码生成规则,将支持代码生成的计划树节点整合在一起,并添加WholeStageCodegenExec
节点标识,执行时生成一段整合后的可执行代码,减少虚函数调用。针对不支持的代码生成的节点,会添加InputAdapter节点进行标识处理。
(3). ApplyColumnarRulesAndInsertTransitions: 基于ColumnarRule扩展的列式转换规则,转换成支持并加速列式数据读写的SparkPlan。转换操作分为三部分: preColumnarTransitions、insertTransitions、postColumnarTransitions。基于pre前置转换处理,根据输出的数据格式处理行转列(RowToColumnarExec)或列转行(ColumnarToRowExec)的数据插入转换。post后置转换处理可实现计划清理或全局执行效率优化。Gluten扩展ColumnarOverrideRules
规则集,基于preOverrides 将SparkPlan转为GlutenPan(Transformer),后置处理中,校验是否支持向量化计算,若不支持则回退处理,若支持则进一步将行转列&列转行相关的GlutenPlan转换为NativeConversion,关联特定Native引擎的物理计划。为提升执行效率,Gluten基于ColumnarCollapseTransformStages
进行全阶段转换优化,其参考CollapseCodegenStages 设计思想,将支持Native转换的操作整合在一起,并添加WholeStageTransformer
节点,不支持Native执行的节点,则添加InputAdapter节点标识处理。Spark从触发执行到真正作业执行主要分为两个阶段:
ColumnarBatch
抽象。Shuffle是影响执行性能的重要一环,对于ShuffleMapTask任务,Spark提供统一的基于行数据模型的ShuffleManager管理。由于向量化计算采用列式数据结构,需要在 Shuffle Write 阶段引入数据列转行处理,在 Shuffle Read 阶段引入数据行转列处理。为提升列式数据的Shuffle读写性能,Gluten扩展ColumnarShuffleManager
实现基于列式数据模型Shuffle管理。
Substrait是基于Protocol Buffersr Plan定义跨语言关系代数的序列化协议,核心是提供SQL计划树的规范,使得这些计划树可以在不同的执行引擎之间转换和优化,解决不同引擎间互操作性差的问题。Gluten选型Substrait 作为跨运行环境/跨语言的计划转换协议,生成Gluten RDD时,将SparkPlan物理计划转为Substrait PB计划树;Task执行时,再将Substrait计划树转为Velox计划树执行。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。