原文作者:
- Saurabh Mahawar, Developer Relations Engineer at IBM
- Naveen Kumar Mahadevuni, Software Engineer, IBM
https://prestodb.io/blog/2026/08/13/inside-velox-open-source-universal-engine-block-for-big-data-and-ai/
什么是Velox?
想象一下,每个汽车制造商都必须为生产的每一种车型从头打造一台全新的发动机——为灵巧的跑车专门设计一款,为重型皮卡设计另一款,再为家用SUV设计截然不同的一款。从历史上看,这正是
科技行业构建数据管理系统的做法:针对交互式分析、批处理或机器学习等特定工作负载,打造数十种专门化、彼此孤立的查询引擎。
为了解决这种严重的碎片化和重复的工程投入,Meta 开发了 Velox:一个面向数据生态系统的革命性开源 C++ “通用引擎模块”。开发者不再需要反复重新造轮子,现在可以将 Velox 这个
高度 优化、高性能的执行库集成到任何系统中。无论是为极速交互式分析(如 Presto)提供动力,支撑大规模批处理(如 Apache Spark),还是驱动机器学习管道(如 PyTorch),
Velox 都可以统一数据处理的底层核心机制,为整个行业带来顶尖的速度、无与伦比的一致性,以及巨大的工程效率提升。
从 Meta 的内部问题到开源系统
到2010年代初,Meta 已经运营着全球最大的数据平台之一,处理来自数十亿用户的数据,同时支撑着数千名工程师运行分析、A/B 测试和机器学习工作负载。随着数据量的不断增长,性能成为
持续的挑战。
Meta 严重依赖 Presto——这是其在2012年创建并开源的分布式 SQL 引擎。尽管对于基于 JVM 的系统而言,Presto 非常高效,但在 Meta 的规模下,JVM 本身却成了瓶颈。垃圾回收、
JIT 编译开销,以及对 SIMD 等现代 CPU 特性的支持有限,使得进一步提升查询性能变得愈发困难。
Prestissimo:对 Native 执行的实验
为了克服这些限制,Meta 启动了 Prestissimo(Presto C++)项目,目标是仅用原生 C++ 重写 Presto 的执行引擎,同时保留 SQL 解析器和查询规划器不变。
在开发过程中,团队意识到他们正在构建的核心组件——列式内存结构、向量化执行、高性能哈希表以及磁盘溢出基础设施——并不是 Presto 所特有的。Spark、流处理系统和
机器学习特征工程管道同样需要这些基础模块。
与其为每个系统单独实现相同的执行引擎,Meta 将这些可复用组件提取出来,组成一个独立的库。这个库就是 Velox——一个共享的高性能执行引擎,能够为多种数据处理框架提供动力。
为什么需要Velox?
1. 数据处理引擎的碎片化
随着数据工作负载从传统的 SQL 分析发展到实时流处理和 AI 管道,业界通过构建专门的执行引擎来应对,例如 Presto、Spark、Trino、Druid、ClickHouse 和 DuckDB。虽然
每个引擎针对不同的应用场景,但它们都独立实现了相同的核心执行原语。
每个项目都构建了自己的:
- 列式内存数据格式
- 表达式求值引擎(Expression evaluation Engine)
- 用于 Join 和 Aggregation 的哈希表
- 溢出到磁盘的底层机制(Spill-to-Disk)
- Parquet 和 ORC 读取器
- SQL 函数,如 SUM()、COUNT(),以及字符串、日期和数组操作
这使得不同组织不得不重复投入数年的工程研发工作。更重要的是,每一个错误修复、优化或硬件改进都必须在每个引擎中单独实现,使得创新缓慢且成本高昂。
2. SQL语义不一致
独立的实现也导致了引擎之间的行为不一致。即使是像 substr()、round() 或 date_trunc() 这样的简单函数,根据执行引擎的不同,也常常产生不同的结果。在 Meta,工程师们
发现同一个字符串函数会有多个实现,每个都使用不同的索引规则和错误处理行为。
这些语义差异使得迁移工作负载变得困难,并削弱了分析结果的可信度。相同的 SQL 查询在不同平台上可能产生不同的答案,这迫使数据团队花费大量时间调试正确性问题,而不是构建
应用程序。
3. JVM性能瓶颈
大多数大规模分析引擎,包括 Presto、Spark 和 Hive,都依赖 Java 虚拟机(JVM)。尽管 JVM 提供了出色的可移植性和开发效率,但它也给高性能分析执行带来了一些限制:
- 垃圾回收在处理大型查询时会导致不可预测的延迟。
- Java 对象开销增加了内存消耗并降低了缓存效率。
- 内存管理方面的控制能力有限,使得一些高级技术难以实现,例如内存 Arena 和高效的磁盘溢写。
- 与现代 CPU 特性(如 SIMD 向量指令(SSE、AVX、AVX2))的交互,其受限程度远高于原生 C++。
随着数据集持续增长,这些限制成为提升查询性能的主要障碍。
架构:Velox 是如何构建的?
在深入探讨架构之前,必须理解一个关键的设计边界:
Velox 是一个执行后端库,而不是一个独立的数据库服务器。
Velox 有意的不包含 SQL 解析器、查询优化器、分布式 RPC 调度器或集群管理器。它将逻辑计划和调度工作留给 Presto 或 Spark 等宿主引擎,这些引擎将序列化的物理
计划树(velox::core::PlanNode)下发给 Velox 工作节点,以便进行超快(ultra-fast)的原生 C++ 执行。
调用系统(集成层):Layer 1
- 功能: 宿主框架(Presto Coordinator 或 Spark Driver)充当“大脑”。它解析您的 SQL 查询,优化执行计划,并将任务分配到集群中。
- 交接: 调用系统将查询编译为完全优化的查询计划(velox::core::PlanNode 树),并将其下发给 Velox 工作节点执行。
执行框架与算子:Layer 2
- Task / Pipeline 执行框架: 创建非阻塞的工作线程(Drivers),以流式方式驱动数据批次通过执行管道。
- 算子(exec/): 物理处理单元,执行表扫描(TableScan)、过滤(Filter)、投影(Project)、多线程连接(HashJoin)、聚合(HashAgg)、排序(Sort)和磁盘溢出(Spiller)。
- 表达式求值(expression/): 将 SQL 数学和字符串表达式编译为快速执行循环(compileExpressions()),并采用公共子表达式消除(CSE)技术。
- 函数(functions/): 内置的标量函数、聚合函数(facebook::velox::exec::Aggregate)和窗口函数库。
- 序列化器(serializers/): 对向量批次进行编码(PrestoVectorSerde、UnsafeRowSerializer),以实现集群节点间超快速的网络数据交换。
核心数据结构与 I/O:Layer 3
- 向量(vector/): 列式内存表示形式。数据按垂直列方式打包(FlatVector、零拷贝的 DictionaryVector、延迟加载的 LazyVector),使 CPU 能够利用 SIMD 指令在每个时钟周期内处理数百个值。
- 类型系统(type/): 管理基本类型和复杂结构(数组、映射、结构体)。
- 连接器(connectors/): 从各种数据源(HiveConnector、TpchConnector)读写数据。
- I/O —— DWIO(dwio/): 针对 Apache Parquet、ORC/DWRF、Meta 的高速列式格式(Nimble)以及文本文件的 I/O 文件读取器。
- Filter 下推: DWIO 读取器直接在存储文件内部评估过滤条件,在将数据加载到内存之前跳过不匹配的行组。
内存、缓存与基础设施:Layer 4
- 内存管理(common/memory/): 在严格的层级结构(MemoryPool)中跟踪 RAM 使用情况。当查询接近内存上限时,MemoryReclaimer 会自动将临时数据溢写到磁盘,从而避免因内存不足(OOM)导致查询崩溃。
- 文件缓存(AsyncDataCache): 异步地将热点元数据和文件数据页缓存在 RAM 中,减少对操作系统页缓存的依赖,避免页缓存抖动。
- 缓冲区与 Arenas(buffer/): 管理连续内存块(Buffer、BufferView、StreamArena、MmapArena)。
- 通用工具(common/): 负责日志处理、指标采集(TraceContext)以及配置管理。
存储与格式:Layer 5
- 连接 Velox 与云对象存储(AWS S3、Azure ADLS、Google Cloud Storage)、分布式文件系统(HDFS、本地磁盘)以及开放表格式(Hive、Apache Iceberg、Delta Lake)的接口层。
实验性加速与数据交换:Layer 6
- GPU 加速: 利用 Wave(Velox 的 CUDA 框架)或 RAPIDS cuDF,将密集的向量计算卸载到 NVIDIA GPU 上执行。
- Breeze:提供底层 SIMD 向量原语,用于构建高性能向量化计算。
- UCX 数据交换: 高速 RDMA 网络 shuffle 插件,用于服务器间超高速数据传输。
一个查询在 Velox 内部的旅程
一个查询在 Velox 内部的执行流程是流线型的、高度向量化的,并且完全在单节点上完成。由于 Velox 是一个执行库而非完整的数据库,它不负责解析 SQL 或执行全局优化。它严格
位于本地数据面(data plane)上,执行已经由 Presto 或 Spark 等上层引擎完全优化好的物理查询计划。
以下是数据在 Velox 中逐步流转的详细过程:
1. 查询交接与转换
- 上层引擎的协调器(Coordinator)解析查询、优化执行计划,并将特定的物理查询计划片段下发给本地主机上的 Velox。
- Velox 接收该物理计划,并将其映射为一个 Task(本地执行单元)。
2. Task 与 Driver 执行
Task 被划分为一个或多个 Pipeline(管道),每个管道由一组可以连续处理数据的算子(Operator)序列组成。每个 Pipeline 由一个或多个 Driver 执行。Driver 是 Velox
的基本调度执行对象,被调度在共享的工作线程池上。如果某个 Driver 被阻塞(例如在等待 I/O 时)、或者运行超过配置的 cpu time slice 后,它会主动让出执行权,以便
其他 Driver 能够继续推进,从而保持 CPU 资源得到充分利用。
注意:Driver 是调度执行对象,而非操作系统线程。它们被调度在由上层引擎管理的工作线程上执行。
3. 管道化扫描与表达式求值
执行开始后,数据通过存储连接器(Connector)和文件读取器进入管道。Velox 通过其 DWIO 层读取 Parquet、ORC/DWRF、Nimble 和 Text 等格式。在扫描过程中,它会应用
列裁剪(Column Pruning)和谓词下推(Predicate Pushdown)等优化技术,确保仅从存储中读取查询所需的列和行组。
数据在内部以列式向量(Columnar Vector)的形式表示,并以批次方式流经执行管道。包括过滤(Filter)、投影(Project)和算术运算在内的表达式求值都在这些向量批次上执行,
这使得引擎能够利用 SIMD 指令和缓存友好的内存访问,从而获得比逐行执行高得多的吞吐量。
4. 内存仲裁与溢写处理
在算子执行过程中,哈希表、聚合缓冲区和排序结构等中间状态会在 Velox 的层级化 MemoryPool(内存池)系统中分配。
当内存使用量接近配置的阈值时,MemoryArbitrator(内存仲裁器)会协调内存回收。支持溢出的那些算子可以将中间状态写入本地存储,从而使得大型分析查询即使在其工作集超过
可用 RAM 时也能继续执行。
这种方式能够最大限度地减少内存不足(OOM)导致的失败,同时保持查询执行过程的可预测性。
5. 结果交付与网络 Shuffle
当最后一个算子完成处理后,生成的列式向量会被准备好以进行交付。
对于单节点执行,向量会被直接返回给调用引擎。而对于分布式执行,输出可能会被序列化为引擎特定的格式(例如 Presto Pages 或 Spark 的 UnsafeRow 表示形式),然后再与
下游工作节点进行数据交换,或返回给上层引擎。
从 Presto 或 Spark 的角度来看,Velox 充当了一个高度优化的执行后端,将优化后的物理计划转换为最终的查询结果。
主要集成场景:Velox 正被应用于哪些系统?
Velox 目前仍在持续快速发展,但已经被 Meta 内部以及更广泛的开源生态中的十多个数据系统集成使用。通过提供一套统一的高性能组件,Velox 正在打通过去彼此割裂、各自独立演进
的数据处理工作负载。
以下是目前一些较具代表性的、正在使用 Velox 的数据管理系统:
1. 交互式分析:Prestissimo(Presto C++)
Presto 是一个分布式查询引擎,用于支撑大规模的交互式 SQL 分析工作负载。传统上,Presto 的 Worker 节点运行在 Java 虚拟机(JVM)之上,而 JVM 在这种场景下长期存在
一些运行时问题,并且垃圾回收会带来较高的开销。
通过 Prestissimo 项目,开发者正在使用完全由 Velox 驱动的 C++ 进程替代传统的 Java Worker。Prestissimo 提供了一个即插即用式的替代实现:它从 Java Coordinator
接收 Presto 的 Plan Fragment,并直接交给 Velox 进行 Native 执行,从而使 Worker 节点完全绕过 JVM,并获得显著的性能提升。
2. 批处理:Apache Spark(Spruce & Gluten)
对于大规模、计算密集型的批处理和 ETL(抽取、转换、加载)工作负载,Velox 已经与 Apache Spark 进行了深度集成。这主要通过两个项目实现:
- Spruce:Meta 内部的集成方案,通过 Spark 内置的 Script Transform 接口,将查询计划 Fragment 卸载到运行 Velox 的外部 C++ 进程中执行。
- Apache Gluten:由 Intel 最初发起的开源项目。Gluten 充当 Spark 与 Native 执行引擎之间的桥梁,基于 Apache Arrow 数据格式和 Substrait 查询计划构建 Java Native Interface(JNI)接口。它将 Spark 的 JVM 与实际的查询执行引擎解耦,使 Spark 能够将计算密集型任务无缝委托给 Velox 执行。
3. 人工智能与机器学习
Velox 最具雄心的能力之一,是打通传统数据分析与人工智能(AI)之间的鸿沟。
- TorchArrow:Velox 作为 TorchArrow 的后端执行引擎。TorchArrow 是一个用于 PyTorch 数据预处理的 Python DataFrame 库。由于数据预处理在 ML 工作负载中可能消耗高达 50% 的资源,因此使用 Velox 可以统一这些数据处理操作,并带来显著的效率提升。
- F3:Meta 的特征工程框架 F3 也正在将其执行引擎与 Velox 统一。这样一来,开发者可以在离线(批处理)和实时环境中使用统一的执行引擎,方便地为机器学习算法提取和生成特征。
实际性能表现:Velox 的实际应用
为了验证 Velox 的 C++ 设计能否真正转化为实际的性能提升,Meta 在多种执行环境下对 Velox 进行了严格的基准测试。结果表明,通过替代传统的 Java 执行层,或者利用专用硬件,
Velox 不仅能够带来显著的性能提升,还能够大幅降低基础设施成本。
1. CPU 基准测试:Presto Java vs. Velox C++(Prestissimo)
Velox 的第一项重要性能验证由 Meta 完成,测试比较了传统的基于 Java 的 Presto 执行引擎与 Prestissimo(采用 Velox C++ 执行引擎的 Presto Worker)。
- 标准 TPC-H(3 TB 数据规模):在由 80 个节点组成的缓存预热(warm-cache)后的集群中,对于 CPU 受限型查询,Velox 带来了接近一个数量级的性能提升。Query 1(Q1)的执行时间提升了 8.4 倍,从 42 秒降低到仅 5 秒;Query 6(Q6)则获得了 9 倍的加速,从 9 秒降低到 1 秒。对于 Q13、Q19 这类 Shuffle 开销较大的查询,性能也提升了一倍。
- 真实生产流量回放(Shadowing Real Production Traffic):为了避免仅依赖合成基准测试,Meta 进一步将来自多个交互式分析工具的真实生产流量进行回放测试。采用 Velox 的 C++ 执行引擎平均获得了 6~7 倍的性能提升,其中相当一部分查询的执行速度超过传统 Java 引擎的 10 倍。
- 服务器数量减少 3 倍:对于基础设施团队而言,最具实际意义的结果可能是集群承载能力的提升。在生产流量 Shadowing 测试中,基于 Velox 的执行栈能够在服务器数量减少至原来的 1/3 的情况下,承载与原生产环境相同的工作负载,同时保持相当甚至更好的性能。也就是说,Meta 可以将原本由 60 台 Java Worker 构成的集群缩减为仅 20 台 Velox Worker。
2. 分布式批处理基准测试:AWS EKS 上的 Apache Spark + Gluten + Velox
为了评估 Velox 在大规模批处理和 ETL 场景下的扩展能力,Amazon Web Services(AWS) 在 Amazon EKS 上使用 Graviton4 节点(r8gd.12xlarge)进行了 3 TB TPC-DS
基准测试。测试比较了原生 Spark SQL 与采用 Apache Gluten + Velox 加速后的 Spark。
- 整体性能提升: Gluten + Velox 技术栈的整体性能提升了 39%,测试套件的总执行时间从 3,650.56 秒降低到 2,239.93 秒,即整体获得 1.63 倍的加速。在全部 103 个查询中,有 81 个查询获得了显著的性能提升。
- 深入分析 Query 93(4.36 倍加速): 在原生 Spark 中,Query 93 的执行时间为 207.9 秒,而采用 Velox 后缩短至 47.7 秒。其主要原因是将 Spark 传统的 SortMergeJoin 替换为 Velox 的 ShuffledHashJoinExecTransformer,并消除了 Join 前的排序操作:
- 其中作为主要性能热点的 Join Stage 包含约 200 个 Task,其整体执行时间从 1 分 16 秒降低到仅 6.5 秒,性能提升约 12 倍。
- 每个 Task 的峰值内存从 3.3 GB(堆内内存,on-heap)降低到仅 80 MB(堆外内存,off-heap)。
- JVM 垃圾回收(GC)时间从 3.6 秒大幅降低到仅 35 毫秒。
- 序列化后的 Shuffle 数据量减少了 24%,从 214.1 GB 降至 162.2 GB,从而显著降低了磁盘和网络 I/O 压力。
- Whole-Stage Codegen 的细微差异: 该基准测试还揭示了一些有意思的架构层面权衡。少数查询的性能出现了退化,其中最明显的是 Q72,其执行速度反而变慢。由于 Velox 没有实现 SortMergeJoin,在某些情况下,它会在下游算子之间产生并物化数百万个较小的 Columnar Batch。相比之下,原生 Spark 的 **Whole-Stage Codegen(全阶段代码生成)**能够将整个数据处理流水线融合成一个 JVM 函数,从而避免中间数据的物化。
这说明:尽管 Velox 本身具有非常高的执行性能,但要充分发挥其优势,仍然需要结合具体的查询模式和 Join 类型进行分析;对于某些特殊场景,不同的执行模型可能导致性能回退。
3. 硬件加速基准测试:基于 NVIDIA cuDF 的 GPU 原生 Velox
通过将 NVIDIA 的 cuDF 库直接集成到 Velox 中,Presto 等上层执行引擎生成的查询计划可以直接转换为基于 GPU 加速的执行流水线。
- 卓越的单节点性能: 在 TPC-H Scale Factor 1,000(SF1000)数据集上,单节点 Presto C++ 在 AMD 7965WX CPU 上执行时耗时 1,246 秒。通过 Velox + cuDF 将整个 Presto 查询计划迁移到 GPU 上执行后,在 NVIDIA RTX Pro 6000 上的执行时间降低到 133.8 秒,在 NVIDIA GH200 Grace Hopper Superchip 上更是降低到惊人的 99.9 秒,相较 CPU 执行实现了超过 12 倍的加速。
- 基于 NVLink 的多 GPU 扩展: 对于分布式查询执行,Velox 支持一种基于 UCX 的 Exchange Operator,能够让整个执行流水线运行在 GPU 上。在一台配备 8 张 NVIDIA DGX A100 GPU 的节点上,通过高带宽的 NVLink 进行数据交换,相比 Presto 默认的 HTTP Exchange,实现了超过 6 倍的性能提升。
无论运行在标准 CPU、现代 Graviton 处理器,还是最先进的 GPU 上,Velox 的向量化 C++ 架构都充分兑现了其性能承诺。通过将高端的数据处理运行时优化能力普及并开放给更广泛
的数据系统,Velox 使企业能够大幅降低查询延迟、消除 JVM 垃圾回收带来的开销,并将硬件资源规模最多降低至原来的 1/3。
结论 & 统一执行的未来
Velox 代表了数据基础设施领域的一次根本性范式转变。通过将通用的执行原语、向量化数据布局、表达式编译器、内存池以及文件读取器等能力抽取出来,统一构建在一个经过高度优化的
C++ 库中,Velox 实现了三个核心目标:
- 卓越的执行效率: 大幅降低查询延迟,消除 JVM 垃圾回收带来的停顿,并将集群所需的服务器数量最多降低至原来的 1/3。
- 语义一致性: 确保 SQL 函数在不同执行系统中产生完全一致的结果,无论查询是在 Spark SQL、Presto C++ 还是 PyTorch 中执行。
- 面向硬件加速: 能够从 x86 和 Graviton4 CPU 平滑扩展到通过 cuDF 使用 NVIDIA GH200 Grace Hopper GPU,从而适配不同层次的硬件计算平台。
延伸阅读 & 参与社区
- GitHub 代码仓库: https://github.com/facebookincubator/velox
- 官方文档: https://facebookincubator.github.io/velox/
- NVIDIA 官方博客: https://developer.nvidia.com/blog/accelerating-large-scale-data-analytics-with-gpu-native-velox-and-nvidia-cudf/
- Apache Spark + Gluten + Velox 基准测试: https://awslabs.github.io/data-on-eks/docs/benchmarks/spark-gluten-velox-benchmark
作者:王冬
PrestoDB Global Committer | Presto Iceberg Code Owner
- GitHub: https://github.com/hantangwangd
- Email: mingwbd@gmail.com