深入 Velox——面向大数据与 AI 的开源“通用引擎底座”)
原文作者Saurabh Mahawar, Developer Relations Engineer at IBMNaveen Kumar Mahadevuni, Software Engineer, IBMhttps://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还是驱动机器学习管道如 PyTorchVelox 都可以统一数据处理的底层核心机制为整个行业带来顶尖的速度、无与伦比的一致性以及巨大的工程效率提升。从 Meta 的内部问题到开源系统到2010年代初Meta 已经运营着全球最大的数据平台之一处理来自数十亿用户的数据同时支撑着数千名工程师运行分析、A/B 测试和机器学习工作负载。随着数据量的不断增长性能成为持续的挑战。Meta 严重依赖 Presto——这是其在2012年创建并开源的分布式 SQL 引擎。尽管对于基于 JVM 的系统而言Presto 非常高效但在 Meta 的规模下JVM 本身却成了瓶颈。垃圾回收、JIT 编译开销以及对 SIMD 等现代 CPU 特性的支持有限使得进一步提升查询性能变得愈发困难。Prestissimo对 Native 执行的实验为了克服这些限制Meta 启动了 PrestissimoPresto C项目目标是仅用原生 C 重写 Presto 的执行引擎同时保留 SQL 解析器和查询规划器不变。在开发过程中团队意识到他们正在构建的核心组件——列式内存结构、向量化执行、高性能哈希表以及磁盘溢出基础设施——并不是 Presto 所特有的。Spark、流处理系统和机器学习特征工程管道同样需要这些基础模块。与其为每个系统单独实现相同的执行引擎Meta 将这些可复用组件提取出来组成一个独立的库。这个库就是 Velox——一个共享的高性能执行引擎能够为多种数据处理框架提供动力。为什么需要Velox1. 数据处理引擎的碎片化随着数据工作负载从传统的 SQL 分析发展到实时流处理和 AI 管道业界通过构建专门的执行引擎来应对例如 Presto、Spark、Trino、Druid、ClickHouse 和 DuckDB。虽然每个引擎针对不同的应用场景但它们都独立实现了相同的核心执行原语。每个项目都构建了自己的列式内存数据格式表达式求值引擎Expression evaluation Engine用于 Join 和 Aggregation 的哈希表溢出到磁盘的底层机制Spill-to-DiskParquet 和 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 2Task / Pipeline 执行框架 创建非阻塞的工作线程Drivers以流式方式驱动数据批次通过执行管道。算子exec/ 物理处理单元执行表扫描TableScan、过滤Filter、投影Project、多线程连接HashJoin、聚合HashAgg、排序Sort和磁盘溢出Spiller。表达式求值expression/ 将 SQL 数学和字符串表达式编译为快速执行循环compileExpressions()并采用公共子表达式消除CSE技术。函数functions/ 内置的标量函数、聚合函数facebook::velox::exec::Aggregate和窗口函数库。序列化器serializers/ 对向量批次进行编码PrestoVectorSerde、UnsafeRowSerializer以实现集群节点间超快速的网络数据交换。核心数据结构与 I/OLayer 3向量vector/ 列式内存表示形式。数据按垂直列方式打包FlatVector、零拷贝的 DictionaryVector、延迟加载的 LazyVector使 CPU 能够利用 SIMD 指令在每个时钟周期内处理数百个值。类型系统type/ 管理基本类型和复杂结构数组、映射、结构体。连接器connectors/ 从各种数据源HiveConnector、TpchConnector读写数据。I/O —— DWIOdwio/ 针对 Apache Parquet、ORC/DWRF、Meta 的高速列式格式Nimble以及文本文件的 I/O 文件读取器。Filter 下推 DWIO 读取器直接在存储文件内部评估过滤条件在将数据加载到内存之前跳过不匹配的行组。内存、缓存与基础设施Layer 4内存管理common/memory/ 在严格的层级结构MemoryPool中跟踪 RAM 使用情况。当查询接近内存上限时MemoryReclaimer 会自动将临时数据溢写到磁盘从而避免因内存不足OOM导致查询崩溃。文件缓存AsyncDataCache 异步地将热点元数据和文件数据页缓存在 RAM 中减少对操作系统页缓存的依赖避免页缓存抖动。缓冲区与 Arenasbuffer/ 管理连续内存块Buffer、BufferView、StreamArena、MmapArena。通用工具common/ 负责日志处理、指标采集TraceContext以及配置管理。存储与格式Layer 5连接 Velox 与云对象存储AWS S3、Azure ADLS、Google Cloud Storage、分布式文件系统HDFS、本地磁盘以及开放表格式Hive、Apache Iceberg、Delta Lake的接口层。实验性加速与数据交换Layer 6GPU 加速 利用 WaveVelox 的 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. 交互式分析PrestissimoPresto CPresto 是一个分布式查询引擎用于支撑大规模的交互式 SQL 分析工作负载。传统上Presto 的 Worker 节点运行在 Java 虚拟机JVM之上而 JVM 在这种场景下长期存在一些运行时问题并且垃圾回收会带来较高的开销。通过 Prestissimo 项目开发者正在使用完全由 Velox 驱动的 C 进程替代传统的 Java Worker。Prestissimo 提供了一个即插即用式的替代实现它从 Java Coordinator接收 Presto 的 Plan Fragment并直接交给 Velox 进行 Native 执行从而使 Worker 节点完全绕过 JVM并获得显著的性能提升。2. 批处理Apache SparkSpruce Gluten对于大规模、计算密集型的批处理和 ETL抽取、转换、加载工作负载Velox 已经与 Apache Spark 进行了深度集成。这主要通过两个项目实现SpruceMeta 内部的集成方案通过 Spark 内置的 Script Transform 接口将查询计划 Fragment 卸载到运行 Velox 的外部 C 进程中执行。Apache Gluten由 Intel 最初发起的开源项目。Gluten 充当 Spark 与 Native 执行引擎之间的桥梁基于 Apache Arrow 数据格式和 Substrait 查询计划构建 Java Native InterfaceJNI接口。它将 Spark 的 JVM 与实际的查询执行引擎解耦使 Spark 能够将计算密集型任务无缝委托给 Velox 执行。3. 人工智能与机器学习Velox 最具雄心的能力之一是打通传统数据分析与人工智能AI之间的鸿沟。TorchArrowVelox 作为 TorchArrow 的后端执行引擎。TorchArrow 是一个用于 PyTorch 数据预处理的 Python DataFrame 库。由于数据预处理在 ML 工作负载中可能消耗高达 50% 的资源因此使用 Velox 可以统一这些数据处理操作并带来显著的效率提升。F3Meta 的特征工程框架 F3 也正在将其执行引擎与 Velox 统一。这样一来开发者可以在离线批处理和实时环境中使用统一的执行引擎方便地为机器学习算法提取和生成特征。实际性能表现Velox 的实际应用为了验证 Velox 的 C 设计能否真正转化为实际的性能提升Meta 在多种执行环境下对 Velox 进行了严格的基准测试。结果表明通过替代传统的 Java 执行层或者利用专用硬件Velox 不仅能够带来显著的性能提升还能够大幅降低基础设施成本。1. CPU 基准测试Presto Java vs. Velox CPrestissimoVelox 的第一项重要性能验证由 Meta 完成测试比较了传统的基于 Java 的 Presto 执行引擎与 Prestissimo采用 Velox C 执行引擎的 Presto Worker。标准 TPC-H3 TB 数据规模在由 80 个节点组成的缓存预热warm-cache后的集群中对于 CPU 受限型查询Velox 带来了接近一个数量级的性能提升。Query 1Q1的执行时间提升了 8.4 倍从 42 秒降低到仅 5 秒Query 6Q6则获得了 9 倍的加速从 9 秒降低到 1 秒。对于 Q13、Q19 这类 Shuffle 开销较大的查询性能也提升了一倍。真实生产流量回放Shadowing Real Production Traffic为了避免仅依赖合成基准测试Meta 进一步将来自多个交互式分析工具的真实生产流量进行回放测试。采用 Velox 的 C 执行引擎平均获得了 67 倍的性能提升其中相当一部分查询的执行速度超过传统 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 ServicesAWS 在 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 934.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,000SF1000数据集上单节点 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 OwnerGitHub: https://github.com/hantangwangdEmail: mingwbdgmail.com