企业宣传,产品推广,广告招商,广告投放联系seowdb

性能提升200% 快手自研Spark向量化引擎正式发布

Blaze 是快手自研的基于Rust语言和DataFusion框架开发的Spark向量化执行引擎,旨在通过本机矢量化执行技术来加速Spark SQL的查询处理。Blaze在快手内部上线的数仓生产作业也观测到了平均30%的算力提升,实现了较大的降本增效。本文将深入剖析blaze的技术原理、实现细节及在快手实际生产环境中的真实表现。

一、研究背景

当下,Spark 的重要发展方向之一是通过向量化执行进一步提升性能。向量化执行的思想是将算子的执行粒度从每次处理一行变成每次处理一个行组,以此来避免大量的函数调用。通过对行组内部处理按列进行计算,同时利用编译技术减少分支判断检查以及更多的 SIMD 优化执行计划。

Blaze 是快手自研的基于Rust语言和DataFusion框架开发的Spark向量化执行引擎,旨在通过本机矢量化执行技术来加速Spark SQL的查询处理。在性能方面,Blaze展现出显著的优势:在TPC-DS 1TB的测试中,Blaze相较于Spark 3.3版本减少了60%的计算时间、Spark 3.5版本减少了40%的计算时间,并大幅降低了集群资源的消耗;此外,Blaze在快手内部上线的数仓生产作业也观测到了平均30%的算力提升,实现了较大幅度的降本增效。

如今,Blaze已开源,拥抱更广阔的开发者社区。开源版本全面兼容Spark 3.0~3.5,用户能够轻松集成Blaze至现有Spark环境中,仅需简单添加Jar包,即可解锁Blaze带来的极致性能优化,享受前所未有的数据处理速度与资源效率。

Github地址:

二、Blaze的整体架构及核心

Spark on Blaze架构的整体流向

Spark+Blaze 的架构设计原理如下图:

对比Spark原生的执行流程,引入Blaze Session Extension组件所带来的作用是显著的,特别是在提升数据处理效率和性能方面。

Spark原生执行流程主要依赖于Java虚拟机(JVM)进行任务的执行,尽管JVM在提供跨平台、内存管理等方面有着卓越的表现,但在大数据处理场景下,尤其是涉及大规模数据计算和复杂查询时,JVM的性能开销可能会成为瓶颈。

Blaze Session Extension组件的引入,巧妙地解决了这一问题。该组件在Spark生成物理执行计划之后介入,通过其翻译逻辑将这一计划转换为等效的、native向量化引擎可以识别的形式,随后提交到Executor端由native引擎执行计算,从而实现了数据处理效率的飞跃。

而这一切的背后,离不开Native向量化引擎这一核心模块的支持。该引擎由Rust语言实现,凭借其卓越的性能、安全性和并发处理能力,成功实现了Spark中大多数关键算子的等效替代,包括但不限于Project、Filter、Sort等。这些经过优化的算子在执行过程中,通过向量化技术显著提升了计算效率,使得数据处理过程更加流畅、快速。

四大核心组件

Blaze 架构中的核心模块有四个,共同驱动着大数据性能的显著提升。这些模块分别为:

具体的执行过程中,遵循以下步骤:

物理执行计划的转换:首先,Spark Extension将 Spark 生成的物理执行计划转换为对应的 Native Plan;

生成和提交Native Plan:转换完成后,Native Plan通过JNI Bridge被提交给Native Engine进行进一步的处理。

Native 执行层:最后,Native Engine利用其高效的内存管理机制和向量化处理技术,对Native Plan进行真正的执行。执行结果通过JNI Bridge返回给Spark,从而完成整个数据处理流程。

三、Blaze的技术优势:面向生产的深度优化

在跑通 tpch 和 tpcds 测试集并取得预期性能提升后,我们面向线上生产环境进一步做了系列深度优化,包括性能和稳定性等方面工作:

细粒度的FailBack机制

我们针对Spark执行效率的提升,设计并实现了演进式向量化执行方案。这一方案旨在逐步优化算子与表达式的向量化覆盖,同时解决Java UDF无法直接转化为Native执行的问题。通过引入细粒度的FailBack机制,Blaze在翻译过程中遇到暂无Native实现的算子、单个表达式或UDF时,支持算子/单个表达式粒度的回退,能够灵活回退到Spark原生执行。此机制首先确定算子/表达式的依赖参数列,利用Arrow FFI技术将这些参数列作为行传递给Spark进行处理,然后将结果以列的形式回传至Blaze,从而在JVM与Native执行之间构建了一座桥梁。

此方案不仅加速了向量化执行的全面部署,还确保了即便在用户SQL中有少量UDF等不支持的场景,细粒度回退单个表达式开销较小,作业整体依然可以得到优化。

更高效的向量化数据传输格式

在Spark中,Shuffle操作因其复杂的数据流转过程成为性能瓶颈,涉及编码、压缩、网络传输、解压及解码等多个环节。原生Spark采用基于行的序列化与压缩方式,而业界向量化数据则倾向于Arrow格式传输,但实践中发现Arrow与主流轻量压缩算法适配不佳,导致压缩率低下且存在冗余信息。针对此问题,Blaze定制了优化的数据传输格式,不仅去除了列名、数据类型等冗余数据,还使用了byte-transpose列式数据序列化技术,通过重组整型/浮点型数据的字节顺序,显著提升数据压缩效率。这一改进大幅减少了Shuffle过程中的数据传输量,并在实际测试与TPC-DS基准测试中展现出显著的性能提升与资源消耗降低,有效解决了原有问题并优化了系统整体性能。

线上2000多个作业的真实数据,上线后输入数据量小幅上涨的情况下,Shuffle数据量相比spark降近30%

减少用户成本的多级内容管理策略

面对Spark与Native执行模式在内存管理上的差异,我们设计了跨堆内堆外的自适应内存管理机制。该机制根据任务的向量化覆盖情况智能调整内存分配,确保资源高效利用。同时,我们构建了堆外内存、堆内内存与磁盘文件之间的多级管理体系,有效防止了内存不足及频繁数据溢写的问题。这些措施不仅保障了向量化引擎上线后任务的稳定运行,无需用户手动调整内存参数,大幅降低了用户操作成本,提升了整体系统的易用性与可靠性。

复杂度更优的聚合算法实现

为深度适配Spark的复杂需求,Blaze在aggregate、sort、shuffle等关键算子的实现上并未直接采用DataFusion的现成方案,而是进行了定制化开发。以HashAggregate为例,当面对大规模group-by聚合且内存不足时,Spark会转而采用基于排序的聚合,这涉及高复杂度的排序与归并过程。而在Blaze中,我们采用了基于分桶的归并方式,利用基数排序在spill时进行分桶、溢写,并在合并阶段通过hash 表快速合并,整个流程保持O(n)的复杂度,显著提升了聚合算子的执行效率与资源利用率。

向量化计算场景的表达式重复计算优化

针对SQL执行中算子间常见的重复表达式计算问题,Blaze借鉴了Spark的Whole-stage codegen技术,应用了这一项优化策略。该策略能够智能识别并合并包含重复表达式的算子,如下图中的Project与Filter合并为一个大算子,并在其中对表达式计算结果进行缓存、复用,达到了减少重复计算、提高执行效率的目的。这一优化在应对复杂计算逻辑(如JSON解析多个字段、UDF调用)时尤为显著,能将执行效率提升一倍以上。特别是在内部业务场景中,对于高频调用的重负载UDF,该优化成功减少了约40%的计算开销,显著增强了系统的整体性能与响应速度。

四、当前进展及未来规划

当前进展

Blaze 作为一款高性能数据处理引擎,已取得了显著进展,全面支持多项核心功能,展现出强大的技术实力与广泛的应用潜力。具体而言,Blaze 目前已具备以下关键能力:

在真实的生产环境中,向量化引擎大规模上线应用,算力平均提升 30%+,成本节约年化数千万元。

未来规划

1、持续迭代优化,内部线上推全:通过不断收集用户反馈与性能数据,我们将精准定位并修复潜在问题,同时引入更多先进的算法与优化策略,以进一步提升Blaze的性能与稳定性。

2、支持更多引擎或场景,例如数据湖等:为了满足用户日益多样化的数据处理需求,我们将不断拓展Blaze的应用场景,支持更多类型的数据处理引擎与场景,如数据湖等。通过加强与业界主流技术的兼容性,我们将为用户提供更加灵活、便捷的数据处理方案,助力用户解锁数据价值,推动业务创新与发展。

3、加强开源社区运营建设,共建生态繁荣:我们深知开源社区对于技术发展与生态繁荣的重要性。因此,我们将在之后加强Blaze开源社区的运营建设,积极构建一个开放、包容、协作的社区环境。当前我们已经与阿里、B站、携程、联通云等公司达成合作。

如果您对该项目感兴趣,欢迎您为项目点个star。项目地址:

© 版权声明
评论 抢沙发
加载中~
每日一言
不怕万人阻挡,只怕自己投降
Not afraid of people blocking, I'm afraid their surrender