Gluten架构揭秘:如何用Substrait实现Spark与原生引擎的无缝集成

📅 2026/6/27 21:17:23
Gluten架构揭秘:如何用Substrait实现Spark与原生引擎的无缝集成
Gluten架构揭秘如何用Substrait实现Spark与原生引擎的无缝集成【免费下载链接】GlutenThis repository is a mirror repository for the integration between the OmniRuntime system and Gluten.项目地址: https://gitcode.com/openeuler/Gluten前往项目官网免费下载https://ar.openeuler.org/ar/Gluten是openEuler社区推出的一款高性能计算加速框架它通过Substrait协议实现了Spark与ClickHouse、Velox等原生引擎的无缝集成显著提升了大数据处理效率。本文将深入解析Gluten的核心架构带你了解Substrait如何打破Spark与原生引擎之间的通信壁垒以及这种集成方案带来的性能优势。为什么需要Substrait传统集成方案的痛点在大数据处理领域Spark作为通用计算引擎被广泛应用但在面对复杂分析场景时其原生执行效率往往难以满足需求。传统的集成方案通常采用以下两种方式JNI直接调用通过Java Native Interface直接调用C编写的原生库这种方式虽然灵活但缺乏统一的接口规范不同引擎间的兼容性差维护成本高。进程间通信将计算任务分发到独立的原生引擎进程中执行通过网络或共享内存进行数据交换这种方式会引入额外的序列化/反序列化开销影响整体性能。Substrait的出现解决了这些痛点它定义了一套跨语言的计算任务描述协议使得Spark可以将物理执行计划以标准化的格式传递给原生引擎实现了计算逻辑的无缝对接。Gluten架构全景Substrait如何连接Spark与原生引擎Gluten的架构设计围绕Substrait协议展开主要包含以下几个核心组件1. Spark插件层Gluten通过Spark插件的方式集成到Spark生态中在Spark Driver端对物理计划进行转换和优化。这一层的核心功能是将Spark的物理计划转换为Substrait计划具体实现代码位于gluten-substrait/src/main/scala/io/glutenproject/substrait/plan/PlanConverter.scala。2. Substrait协议层Substrait协议层负责定义计算任务的标准化表示包括关系代数、数据类型、函数签名等。Gluten对Substrait协议进行了扩展以支持Spark特有的数据类型和函数相关代码可以在gluten-substrait/src/main/proto/substrait_extensions.proto中找到。3. 原生引擎适配层原生引擎适配层负责将Substrait计划转换为具体原生引擎的执行计划并调度执行。目前Gluten支持ClickHouse、Velox等多种原生引擎其中ClickHouse的适配代码位于cpp-ch/local-engine/Parser/RelParsers/目录下Velox的适配代码则位于cpp/velox/substrait/目录。如图所示Spark通过Gluten插件将物理计划转换为Substrait计划然后通过JNI调用将Substrait计划传递给原生引擎。原生引擎执行完成后将结果返回给Spark整个过程中数据以列存格式在内存中直接传递避免了不必要的序列化/反序列化开销。Substrait计划转换从Spark物理计划到原生执行计划Gluten实现Spark与原生引擎无缝集成的核心在于Substrait计划的转换这一过程主要包括以下几个步骤1. Spark物理计划优化在转换为Substrait计划之前Gluten会对Spark的物理计划进行优化例如合并相邻的Project操作、下推Filter条件等。这一步的目的是减少不必要的计算提高执行效率。2. Substrait计划生成Gluten通过PlanConverter将优化后的Spark物理计划转换为Substrait计划。Substrait计划采用Protocol Buffers格式进行序列化便于在不同语言之间传递。相关的转换逻辑可以在gluten-substrait/src/main/scala/io/glutenproject/substrait/plan/PlanConverter.scala中查看。3. 原生引擎执行计划生成原生引擎接收到Substrait计划后会将其转换为自身的执行计划。以ClickHouse为例Gluten通过cpp-ch/local-engine/Parser/RelParsers/目录下的代码将Substrait计划转换为ClickHouse的AST然后由ClickHouse引擎执行。如图所示Spark物理计划经过Transformer转换为Substrait计划然后传递给原生引擎执行。原生引擎执行完成后通过Columnar Shuffle将结果返回给Spark。核心技术解析Gluten如何保证高效集成1. 列存数据格式Gluten采用Arrow列存格式作为数据交换的标准避免了Spark默认行存格式与原生引擎列存格式之间的转换开销。相关的实现代码可以在gluten-arrow/src/main/scala/io/glutenproject/arrow/目录下找到。2. 向量化执行Gluten充分利用原生引擎的向量化执行能力通过Substrait计划将计算任务下推到原生引擎执行减少了Java与原生代码之间的上下文切换开销。例如Velox引擎的向量化执行代码位于cpp/velox/operators/目录。3. 算子下推Gluten支持将Spark的部分算子下推到原生引擎执行例如Filter、Project、Aggregate等。这一功能的实现依赖于Substrait协议对算子的标准化描述相关代码可以在gluten-core/src/main/scala/io/glutenproject/execution/目录下查看。如图所示Gluten定义了多种Transformer用于将不同类型的Spark物理算子转换为Substrait计划。这些Transformer包括SubstraitTransformerExec、ConditionProjectExecTransformer、HashJoinTransformer等分别对应不同的Spark物理算子。性能优势Substrait集成方案带来的提升通过Substrait协议实现Spark与原生引擎的无缝集成Gluten在性能上带来了显著提升。根据官方测试数据在TPC-H基准测试中GlutenClickHouse的性能相比Spark原生实现提升了2-5倍部分查询甚至达到了10倍以上的性能提升。如图所示在TPC-H 10个查询的测试中GlutenClickHouse的性能明显优于Spark原生实现。这种性能提升主要来自于以下几个方面减少数据转换开销通过Arrow列存格式和Substrait计划避免了不必要的数据转换和序列化/反序列化开销。利用原生引擎优势原生引擎如ClickHouse、Velox在查询优化、向量化执行等方面具有优势Gluten将计算任务下推到这些引擎执行充分发挥了它们的性能潜力。减少JVM开销将计算任务下推到原生引擎执行减少了Spark JVM的内存占用和GC压力提高了系统的稳定性和吞吐量。快速开始如何使用Gluten如果你想体验Gluten带来的性能提升可以按照以下步骤进行操作克隆Gluten仓库git clone https://gitcode.com/openeuler/Gluten参考官方文档进行编译和安装docs/get-started/ClickHouse.md配置Spark使用Glutenspark-shell --conf spark.pluginsio.glutenproject.GlutenPlugin \ --conf spark.gluten.sql.columnar.backendclickhouse运行你的Spark作业体验性能提升。总结Gluten通过Substrait协议实现了Spark与原生引擎的无缝集成打破了不同计算引擎之间的通信壁垒充分发挥了原生引擎的性能优势。这种架构设计不仅提升了大数据处理的效率还为不同计算引擎的协同工作提供了新的思路。随着Substrait协议的不断完善和Gluten社区的持续发展相信Gluten将会在大数据处理领域发挥越来越重要的作用。如果你对Gluten的架构和实现细节感兴趣可以查阅官方文档docs/developers/HowTo.md或者参与社区讨论为Gluten的发展贡献力量。【免费下载链接】GlutenThis repository is a mirror repository for the integration between the OmniRuntime system and Gluten.项目地址: https://gitcode.com/openeuler/Gluten创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考