资讯详情

资讯详情

Presto 查询引擎内核详解:整体架构与查询执行流程

一、Presto 查询引擎整体架构Presto 是一个面向交互式分析场景设计的分布式 SQL 查询引擎。它的核心目标是将用户提交的 SQL 查询转换为分布式执行计划并通过 Coordinator 进行任务调度最终驱动 Worker 节点上的算子流水线执行。从查询执行架构来看Presto 可以划分为三个核心部分其中Coordinator 负责查询生命周期管理、逻辑优化以及分布式调度Worker 负责具体的数据计算与执行流水线运行Connector SPI 负责连接计算引擎与外部数据源一方面向 Coordinator 提供元数据描述和数据源能力信息支持谓词下推、聚合下推、分区裁剪、基于统计信息的优化等查询优化能力另一方面向 Worker 提供 PageSource、PageSink 等数据读写接口完成实际的数据访问。查询执行过程围绕 Query、Stage、Task、Driver、Operator 等执行对象展开而 Connector SPI 则实现了计算引擎与底层存储系统之间的解耦。理解这些对象之间的关系是理解 Presto 内核实现的基础。二、一条 SQL 在 Presto 中的完整生命周期一条 SQL 从提交到最终返回结果需要经历多个抽象层次转换Presto 并不是直接执行 SQL而是逐层将用户表达转换为可执行模型。2.1 查询准入与资源管理提交查询后Presto 首先通过 Resource Group 对查询进行分类和管理。Resource Group 根据用户查询标签用户组查询特征将查询映射到对应资源组并实施并发限制CPU资源限制内存限制排队策略。它是 Coordinator 层面保证多租户环境稳定运行的重要机制。2.2 Connector SPI连接查询优化与数据访问Presto 通过 Connector SPI 实现计算引擎与外部数据源之间的解耦。Connector 并不仅仅负责 Worker 阶段的数据读取而是贯穿查询规划、优化以及执行全过程。在 Planning 和 Optimization 阶段Coordinator 会通过 Connector 获取外部数据源提供的元信息和能力描述包括Schema 信息Table / Column MetadataPartition 信息StatisticsConnector 支持的 Pushdown 能力。这些信息会参与表结构解析查询优化Predicate PushdownProjection PushdownAggregation PushdownPartition Pruning基于统计信息的成本优化。在执行阶段Worker 根据 Coordinator 生成的执行计划通过 Connector 创建具体的数据访问对象TableScan Operator -- Connector PageSource -- External StorageConnector 负责将外部数据转换为 Presto 内部统一的数据表示External Data -- Connector -- Page/Block -- Operator Pipeline同时在写入场景下Connector 通过 PageSink 接收执行结果并完成目标系统的数据写入。三、SQL解析与语义分析从 SQL 文本到语义绑定模型3.1 StatementSQL 的抽象语法树用户提交的 SQL 首先经过 Parser 解析。Parser 基于 ANTLR 完成 SQL 文法解析并通过 AstBuilder 将解析结果转换为 Presto 内部的 AST Node 层次结构 Statement。Statement 是 SQL 顶层语法结构的抽象表示不同 SQL 类型对应不同 Statement 子类包括 Query、Insert、CreateTable 等。例如对于查询语句来说其内部包含的属性有查询主体 QuerySELECT 列表FROM 子句WHERE 条件GROUP BYORDER BYLIMIT。对于包含子查询的 SQLStatement 本身也是递归结构。例如SELECT * FROM ( SELECT id FROM table_a )内部会形成多层 Query 结构。3.2 Analysis完成语义绑定Parser 只能理解 SQL 结构而无法判断表是否存在字面量的列名到底指向的是哪个表的哪个列数据类型是否匹配函数是否有效。因此 Presto 需要 Analyzer 对 AST 进行语义分析。并使用 Analysis 保存语义分析结果例如表和列的绑定关系类型推导结果表达式解析信息。Analyzer 基于 Visitor 模式自顶向下遍历 AST并在分析过程中逐步构建语义上下文。这一阶段完成了从“SQL语法”到“SQL语义”的转换。四、逻辑计划生成与优化从 SQL 到执行策略4.1 Logical Plan经过 Analyzer 后LogicalPlanner 根据 Analysis 中的语义信息将 Statement 转换为逻辑计划 Plan。Plan 本质上是一棵由 PlanNode 组成的树OutputNode | AggregationNode | JoinNode / \ ScanNode ScanNode每一个 PlanNode 描述一种逻辑操作TableScanNode读取数据FilterNode过滤JoinNode关联AggregationNode聚合SortNode排序。PlanNode 是 Presto 内部统一的查询计划表示。LogicalPlanner 根据语义分析结果生成初始 PlanNode 树Optimizer 在此基础上不断重写和增强计划使其逐渐包含执行策略信息。4.2 Optimizer生成优化后的执行计划Presto 在 Logical Plan 基础上执行一系列优化规则将初始计划转换为更加高效的执行计划。优化过程包括谓词下推列裁剪Join 类型选择Join 顺序调整数据分布策略选择Exchange 规划Local Exchange 规划等等。例如Logical Join | Optimizer v Broadcast Join or Partitioned Join优化后的 Plan 仍然保持统一的 PlanNode 树结构但已经融合了更多执行相关的信息包括数据分布方式、Join 策略以及后续执行阶段所需的物理属性。需要注意的是Presto 的优化体系并不是严格区分 Logical Optimization、Physical Planning 和 Cost Based Optimization 的单一阶段而是在统一的 Plan 优化框架中融合了多种优化能力基于规则的优化Rule-based Optimization例如谓词下推、列裁剪等基于成本的优化Cost-based Optimization例如 Join Reordering、Join Distribution Selection 等面向执行的物理规划能力Physical Planning例如 Exchange 和 Local Exchange 的生成。最终Optimizer 输出的是一个经过优化并包含执行策略信息的物理执行计划后续将由 Distributed Planning 和 Scheduler 进一步转换为可调度执行的 Stage 和 Task。五、从执行计划到分布式执行图物理计划描述的是单个查询的计算逻辑而分布式执行还需要进一步划分执行阶段。5.1 Remote ExchangeStage切分边界Presto 根据 Remote Exchange 对执行计划进行切分而 Local Exchange 仅用于单个 Worker 内部的数据重分布不形成新的 Stage。Remote Exchange 表示数据需要跨 Worker 节点进行交换。因此Plan Tree | Remote Exchange | Stage BoundaryRemote Exchange 会形成 Stage 之间的数据交换边界使 Exchange 两侧的计划片段分别属于不同 Stage。5.2 Stage 与 PlanFragment在分布式规划阶段Presto 将执行计划切分为多个 SubPlan。每个 SubPlan 包含一个 PlanFragment以及由 Remote Exchange 引出的子 SubPlan 依赖关系PlanFragment子 SubPlan 列表。PlanFragment 是分布式规划阶段生成的静态执行计划片段描述单个 Stage 内的计算逻辑运行时 Coordinator 基于 PlanFragment 创建对应 Stage并负责调度执行。运行时Coordinator 根据这些 SubPlan 创建对应 Stage并负责调度执行。在传统 Presto 执行模型中Stage 通常形成树形依赖关系Stage 0 | Stage 1 / \ Stage 2 Stage 3这与 Spark 基于 Shuffle DAG 的执行模型不同。Presto 更强调数据流式传递Pipeline 执行减少中间结果物化。需要说明的是在传统流式执行模型中Stage 通常按照 Exchange 形成的数据流依赖关系进行调度。但随着 Exchange Materialization 能力的引入Presto 在保留Pipeline Streaming 优势的同时也具备了一定程度的阶段化物化执行能力。Section 用于组织相关 Stage 的执行依赖使部分查询可以通过物化结果建立阶段边界从而提升大规模数据处理能力、执行稳定性以及容错能力。相比纯流式执行模式该方式会引入额外的存储和 I/O 开销但扩展了 Presto 能够支持的 workload 范围。Stage 是分布式调度的基本单位而真正下发到 Worker 执行的数据处理任务则会进一步通过 Split 进行划分。后续调度流程会围绕 Stage、Task、Split 之间的关系展开。六、Coordinator 查询调度模型从 Stage 到 Task 的分布式执行编排生成 Stage 后Coordinator 开始负责整个 query 的分布式调度。整体流程如下Query | SqlQueryScheduler | SectionExecution | StageScheduler | RemoteTask | Worker6.1 Query级调度SqlQueryScheduler 是查询级调度入口。 它负责管理 Section创建 StageExecution调度 Stage维护 Stage 之间的数据依赖。Presto 会根据 Section 依赖关系选择当前可以执行的部分。调度时SqlQueryScheduler 根据查询执行图创建 SectionExecution并生成对应的 ExecutionSchedule。ExecutionSchedule 根据 Stage 依赖关系决定当前可调度的 Stage。6.2 Section级调度Section 是对 Stage 调度的一层组织抽象其主要作用包括将具有流式 Exchange 依赖关系的 Stages 组织在同一个 Section 内以支持 Pipeline Streaming 执行根据 Exchange Materialization 等阶段化执行依赖将部分 Stages 划分到不同 Section 中Section 之间通过依赖关系控制执行顺序使 Presto 能够在流式执行和物化执行混合场景下更好地支持大规模查询执行、失败恢复以及 Runtime CBO 等运行时优化能力。Section 内部可以包含多个 Stage。一个 Section 在调度其内部包含的 Stage 时可以有不同的调度策略AllAtOnceExecutionSchedule一次调度 Section 内全部 Stage。PhasedExecutionSchedule将 Stage 划分多个 phase 按顺序进行调度以控制资源使用Phase 1 -- Phase 2 -- Phase 3这两种策略分别对应一次性调度和分阶段调度。6.3 Stage调度StageScheduler 是具体 Stage 的调度实现。它负责创建 Task选择 Worker 节点消费 SplitSource并分配 Split。不同 Stage 类型会对应不同 SchedulerSourcePartitionedSchedulerFixedCountSchedulerFixedSourcePartitionedSchedulerScaledWriterScheduler。Presto 根据 Stage 类型和数据分布策略选择不同 StageScheduler 实现这些不同的实现类型采用不同的策略和逻辑来决定如何创建任务以及分配资源。七、Worker 执行模型Task、Driver 与 Pipeline ExecutionCoordinator 完成 Task 调度后Worker 开始实际执行任务。Worker 内部执行层次如下所示7.1 TaskTask 是 Worker 上执行某个 Stage 对应 PlanFragment 的基本实体。在实际调度运行的过程中Coordinator 根据 Stage 的调度策略选择 Worker 节点并通过 RemoteTask 代理管理 Worker 上对应 Task 的生命周期。7.2 LocalExecutionPlanWorker 接收到 PlanFragment 后会转换成本地执行计划 LocalExecutionPlan其中包含DriverFactoryOperatorFactory。在分布式规划阶段PlanFragment 描述的是一个 Stage 内的整体计算逻辑而到了 Worker 执行阶段该计划会进一步转换为一个或多个本地执行 Pipeline。每个 Pipeline 由一组按照数据流连接的 Operator 组成并最终由 Driver 负责驱动执行。此外在 Pipeline 执行模型中的另一个重要概念是 Lifespan。Lifespan 是 Presto 实现数据‘分组’Grouped Execution执行的关键。它让同一个 Stage 中属于不同数据组例如Hive表的不同Bucket的 Split可以在同一个 Worker 节点上的不同 Driver 中并发执行。Pipeline | ---------------- | | Lifespan A Lifespan B | | Driver(s) Driver(s)综上所述PlanFragment 描述分布式执行阶段中的计算逻辑LocalExecutionPlan 描述 Worker 内部如何组织这些计算逻辑Pipeline 描述 Worker 内部的数据处理流水线在 LocalExecutionPlan 中通过 DriverFactory 来表达Driver 表示一个 Pipeline 在特定 Lifespan 下的一次执行实例。LocalExecutionPlan 通过 DriverFactory 创建 Driver并通过 OperatorFactory 创建具体 Operator从而将逻辑计划转换为 Worker 可执行的数据处理流水线。7.3 DriverPipeline 执行实例核心对象Driver 是 Presto Worker 中表示一次 Operator Pipeline 执行实例的核心对象。如上所述其结合了 Pipeline算子链执行逻辑和 Lifespan 数据分组两个维度。Driver 本身不是线程也不与固定线程绑定而是一个轻量级的执行流水线实例。它负责按照 Operator Pipeline 的定义持续处理 Page并驱动各个 Operator 完成数据计算。例如TableScanOperator -- FilterOperator -- ProjectOperator -- OutputOperatorDriver 按照 Pipeline 定义的 Operator 顺序持续处理数据流 Pages。需要注意的是Driver 并不是 Worker 调度系统直接管理的最小调度单元。为了支持优先级调度、时间片执行以及阻塞恢复Presto 会将 Driver 封装为 DriverSplitRunner / PrioritizedSplitRunner并交由 TaskExecutor 进行调度执行。7.4 SplitRunnerWorker 调度层的最小执行单元Presto Worker 并不是直接调度 Driver而是将 Driver 封装为 SplitRunner。核心关系TaskExecutor | 调度执行 v PrioritizedSplitRunner -- DriverSplitRunner -- Driver其中Driver 表示一个结合了 Pipeline算子链执行逻辑和 Lifespan数据分组两个维度的执行流水线SplitRunner 是对 Driver 的封装用于代表一次具体执行PrioritizedSplitRunner 进一步提供优先级和时间片调度能力。一个 Pipeline 根据不同 Lifespan 可以产生多个 Driver / DriverSplitRunner。从职责划分来看Presto Worker 执行模型可以分为两个维度计算模型Pipeline - Driver - Operator - Page调度模型TaskExecutor | v SplitRunner - Driver 执行这种计算与调度分离的设计使 Presto 能够在 Worker 内部实现细粒度资源分配与基于语义的公平调度而不是将线程直接绑定到查询任务上。八、数据流执行模型Split、Page、Exchange8.1 Split数据调度单元Split 是 Connector 根据外部数据源特征生成的可调度数据处理单元是连接数据源访问和 Worker 执行的桥梁。 例如Hive Connector 根据文件生成 SplitIceberg Connector 根据数据文件生成 Split。Split 本身并不包含实际数据而是描述如何访问一部分数据的信息。Coordinator 在查询规划阶段通过 Connector SPI 创建对应的数据源 SplitSource并在调度阶段由 StageScheduler 获取 Split并将其分配给 Worker Task。8.2 Page执行中的数据表示Presto 内部采用基于 Page / Block 的列式批量数据处理模型。Page 是 Operator 之间传递的数据批次。一个 Page 由多个 Block 组成Page ------------------ | | | | Block0 Block1 Block2 ... Column0 Column1 Column2 ...其中Page 表示一批数据Block 表示单个列的数据存储结构。这种列式数据表示方式使 Operator 可以高效进行向量化计算提高 CPU Cache 利用率并减少数据复制开销。同时基于列式数据表示Presto 可以更高效地配合查询优化阶段的列裁剪Projection Pruning和 Connector 层的列投影下推仅生成和处理查询所需的数据列从而降低数据处理开销。8.3 ExchangeWorker之间的数据传输当查询涉及多个 Stage 时不同 Worker 之间需要交换中间结果。例如Worker A | Remote Exchange | Worker B实际运行时Source Task | OutputBuffer | ExchangeClient | Destination Task其中上游 Task 将结果写入 OutputBuffer下游 Task 通过 ExchangeClient 拉取 PagePage 继续进入后续 Operator Pipeline。Presto 使用 ExchangeClient 接收远程 Task 输出的数据。ExchangeClient 负责管理来自多个上游 Task 的数据拉取并将接收到的数据转换为 Page 流交给下游 Pipeline 继续处理。需要注意的是Remote Exchange 用于跨 Worker / Stage 的数据交换而 Local Exchange 仅用于单个 Worker 内部的数据重新分布不形成新的 Stage。九、Presto 查询引擎的核心设计思想通过上述各个章节的描述可以看到Presto 的整体设计围绕几个核心思想展开。9.1 分层抽象从 SQL 语义到执行模型逐层映射Presto 将查询处理过程拆分为多个抽象层次SQL | Statement / AST | Analysis | Logical Plan | Optimized Physical Plan | Stage / PlanFragment | Task | Driver Pipeline | Operator | Page每一层承担不同职责Analyzer 负责理解 SQL 语义Planner / Optimizer 负责生成执行策略Distributed Planner 负责形成分布式执行结构Worker Runtime 负责高效执行数据计算。这种分层设计使 SQL 语义、执行策略以及运行时实现相互解耦是 Presto 能够持续演进 Connector、Optimizer 和 Execution Runtime 的基础。9.2 Pipeline Streaming面向低延迟分析的执行模型Presto 面向交互式查询场景设计其核心执行理念是 Pipeline Streaming。与传统批处理系统依赖 Stage 边界进行大量中间结果物化不同Presto 更倾向于让数据持续流动。这种设计带来的优势减少中间结果写入和读取降低端到端查询延迟提升交互式分析体验。同时Exchange Materialization 等能力的引入使 Presto 在保持流式执行优势的同时也逐渐具备阶段化物化执行能力以支持更大规模、更复杂的 workload。9.3 细粒度调度计算实体与调度实体分离Presto Worker 并不是直接以 Query 或 Task 作为调度单位而是进一步拆分到 Driver/SplitRunner 层面。其中Driver 表示计算流水线实例SplitRunner 表示可调度执行封装TaskExecutor 负责多个执行实体之间的资源调度。这种设计使计算逻辑和资源调度解耦从而多查询共享 Worker 执行资源限制长查询对短查询的影响支撑交互式负载下的低延迟响应。9.4 Connector SPI计算与数据能力解耦Presto 并不直接管理底层存储而是通过 Connector SPI 将计算引擎与数据源能力解耦。Connector 一方面向 Coordinator 提供MetadataStatisticsPushdown 能力描述Partition 信息。另一方面向 Worker 提供SplitPageSourcePageSink。这种设计使 Presto 能够通过统一 SQL 接口访问不同数据系统并将优化能力逐渐扩展到数据源侧。总体来看Presto 的设计并不是简单追求单点性能而是在 SQL 抽象、分布式执行、资源调度以及数据源扩展性之间建立了一套高度解耦的执行体系使其能够在交互式分析场景下提供低延迟、高扩展的数据查询能力。十、后续系列文章规划本文作为《Presto 查询引擎内核详解》的架构地图后续将围绕查询生命周期深入分析各核心模块SQL Analyzer语义分析与符号解析体系Logical Planner从 AST 到关系型执行计划的生成过程Optimizer规则优化、成本优化与物理计划优化体系Physical PlanExchange规划与执行属性约束机制Distributed ExecutionStage切分、PlanFragment生成与分布式执行规划Query Scheduling查询调度、Stage调度与Split分发机制Worker Execution ModelTask、Driver与Pipeline执行模型Worker 调度模型基于多级反馈队列思想的执行实体调度机制Exchange机制分布式数据交换与流式执行体系Memory Management查询内存模型、内存池与资源控制机制Transaction Manager事务管理与一致性控制Vectorized ExecutionPage/Block模型与向量化执行优化可撤回内存与 Spill 机制Presto 查询执行的内存弹性机制Materialized View基于增量维护和查询重写的物化视图体系Iceberg Connector湖仓表格式集成、谓词下推、事务支持与元数据优化Presto 下一代执行引擎Prestissimo 与 Velox 架构演进待补充完善…通过这些章节可以逐步深入 Presto 从 SQL 输入到分布式执行完成的完整内部机制。作者王冬PrestoDB Global Committer | Presto Iceberg Code OwnerGitHub: https://github.com/hantangwangdEmail: mingwbdgmail.com本文章同步发表于https://hantangwangd.github.io/zh/posts/2026-08-04-whole-architecture-and-query-execution-flow.html
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →