趋近智
现代数据湖依赖于计算与存储的分离。虽然这种架构降低了存储成本并提高了扩展性,但它在处理引擎和数据持久化层之间引入了物理隔离。与传统关系型数据库管理系统 (RDBMS) 中引擎直接本地访问底层存储介质不同,数据湖查询引擎必须通过网络从对象存储服务(如 Amazon S3、Azure Data Lake Storage 或 Google Cloud Storage)获取数据。
为弥合此差距并提供交互式性能,我们采用构建在大规模并行处理 (MPP) 架构上的分布式 SQL 引擎。现代数据技术栈中最常见的例子是 Trino(前身为 PrestoSQL)、Apache Spark SQL 和 Apache Hive LLAP。这些系统通过将工作分发到服务器集群来处理PB级数据,使您能够运行标准 ANSI SQL 查询。
在 MPP 系统中,处理工作负载由许多独立节点分担。这些节点不共享内存或磁盘空间(一种“无共享”架构)。它们仅通过网络进行通信和数据交换。
该架构通常由两种主要节点类型组成:
当查询被提交时,协调器将查询分解为阶段。这些阶段进一步划分为任务,任务并行处理。
以下图表描绘了 Trino 等典型分布式查询引擎中的控制流和数据流。
协调器管理查询计划并分配任务给工作器,工作器直接与存储层交互。
了解 SQL 语句如何变为分布式操作对性能调优很重要。如果查询缓慢,瓶颈通常在这个生命周期的一个特定阶段。
当协调器收到 SQL 语句时,它首先检查语法。然后,它查询元数据目录(例如 Hive Metastore 或 AWS Glue)以验证表和列是否存在,以及用户是否拥有所需权限。在此阶段,查询是一个抽象语法树。
引擎将语法树转换为逻辑计划。这是基于成本的优化器 (CBO) 工作的地方。CBO 评估执行查询的不同方式。例如,如果您要将一个小型“产品类别”表与一个大型“销售”表连接,CBO 会决定是将小表广播到所有节点,还是对大表进行混洗。
优化器使用统计数据(行数、列的不同值、最小值/最大值)来估算操作成本。如果您的元数据目录中缺少这些统计数据,引擎可能会选择一个低效的计划,导致性能缓慢。
逻辑计划被转换为由阶段组成的物理计划。
协调器将这些阶段分解为分片。分片是一个并行单位。在数据湖的背景下,一个分片通常对应于对象存储中文件内的特定字节范围。
工作器执行分配的分片。如果查询是简单的 SELECT * FROM table WHERE id = 1,则操作是“极其并行”的。每个工作器扫描其分配的文件,过滤行,并返回匹配项。
然而,如果查询包含 GROUP BY 或 JOIN,数据必须在工作器之间移动。这个过程称为混洗。
例如,要按 region_id 统计销售额,所有属于 region_id=1 的行必须汇聚到同一个工作节点才能计数。由于原始文件很可能随机分散,工作器实质上通过集群网络交换数据。
在数据湖架构中,(列出文件并与 S3 建立 HTTP 连接)和 常常主导执行时间。
尽管大多数分布式引擎共享上述架构,但它们在处理内存限制方面有所不同。
交互式引擎(例如 Trino, Presto): 这些引擎旨在提高速度。它们试图将所有中间数据保存在内存中。如果查询需要的内存超过集群可用内存(例如,大规模哈希连接),查询将因“内存不足”(OOM)错误而失败。这使它们非常适合即席分析和仪表盘制作,但对大型 ETL 作业的弹性较差。
批处理引擎(例如 Apache Spark): Spark 旨在实现弹性和吞吐量 (throughput)。如果在大型连接或排序过程中内存耗尽,Spark 会将数据“溢出”到工作节点的本地磁盘。查询将继续运行,尽管速度较慢,而不是失败。这使得 Spark 成为第3章中所述大型数据工程管道和摄取作业的首选。
由于引擎通过网络与存储通信,减少传输的数据量是最有效的优化方法。
WHERE 子句)下推到尽可能低的级别。如果使用 Parquet 等格式,工作器可以检查文件尾部统计信息,如果数据范围不符合过滤器,则完全跳过该文件。SELECT * 的成本显著高于 SELECT id, value,因为它迫使工作器从对象存储中读取并传输每一列。了解到查询引擎是一个编排网络请求和内存缓冲区的分布式系统,您可以编写与引擎优势相符的 SQL,特别是通过尽早过滤和只选择必要的列。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造