Presto实战摘要
Presto介绍
大数据带来的问题
数据存储的机制日益多样,缺乏标准的工具查询和检视数据。
数据分散在各个孤岛上。
Presto来救场
Presto是一个开源的分布式SQL查询引擎。它是为了高效查询不同系统和各种规模(GB级到PB级)的数据源的一套系统。
特点:
- 为性能和规模而生
- SQL-on-Anything
- 存储和计算分离
Presto使用场景
- 单一的SQL分析访问点
- 数据仓库和数据源系统的访问点
- 提供对任何内容的SQL访问
- 联邦查询
- 虚拟数据仓库的语义层
- 数据湖查询引擎
Presto资源
注:presto的创始人和Facebook管理层对presto发展的理念不合,presto的创始人离职继续presto的开发,更名为trino,Facebook的presto后来捐给了Linux基金会,也就是prestodb。从github的insight来看,trino的贡献者远超prestodb。
安装Presto
参考官方文档:https://trino.io/docs/current/installation/deployment.html
使用Presto
Presto CLI
参考官方文档:https://trino.io/docs/current/installation/cli.html
Presto JDBC驱动
JDBC 驱动可以让你使用许多强大的 SQL 客户端和数据库管理工具,比如开源工具DBeaver 或 SQuirreL SQL 客户端等。
基于 JDBC 的报告生成、仪表盘和分析工具也可以与 Presto 一起使用。
Presto与ODBC
客户端库
参考官方文档:https://trino.io/resources.html
Presto Web UI
使用Presto执行SQL
连接器
使 Presto 适配一个数据源。每一个 catalog 对应于一个特定的连接器。
Calatlog
定义连接到一个数据源的细节。它包含了 schema 并配置了一个连接器来使用。
Schema
组织表的一种方式。catalog 和 schema 一起定义了一个集合的表,这些表可以查询。
Table
表是无序的行的集合。这些行内容被组织成带有数据类型的有名称的列。
Presto的架构
集群中的协调器和工作节点
协调器用于接受用户查询并管理工作节点以执行查询工作。
工作节点负责执行任务和处理数据。
协调器上通常会运行一个节点发现服务(discovery service),工作节点通过注册到此服务以加入集群。

协调器
Presto 协调器负责接收用户 SQL 查询、解析查询语句、规划查询执行并管理工作节点。协调器是 Presto 集群的大脑,所有客户端应用程序都会连接它。
节点发现服务
Presto 使用节点发现服务来发现集群中的所有节点。每个 Presto 实例在启动时都会注册到发现服务并定期发送心跳信号。
工作节点
工作节点是 Presto 集群中的一个服务端程序。它负责执行协调器分配的任务并处理数据。工作节点使用连接器从数据源获取数据,它们相互之间也会交换中间数据。它们将最终的结果数据发送给协调器,由协调器负责收集来自各个工作节点的结果并发送给客户端。
基于连接器的架构
Presto 存储与计算分离的核心是基于连接器的架构。连接器为 Presto 提供了连接任意数据源的接口。每个连接器在底层数据源上提供了一个基于表的抽象。
查询执行模型
Presto 如何处理实际的 SQL 查询语句。我们先仔细了解一下协调器内部的情况。SQL 语句首先以文本形式提交到协调器,协调器解析和分析这条语句,之后创建一个由 Presto 内部数据结构表示的执行计划,叫作查询计划。
协调器通过元数据 SPI 获取表、列和数据类型的信息。这些信息用于对查询进行语义校验、类型检查和安全检查。
统计 SPI 用于获取行数和表大小的信息,从而在计划期间进行基于代价的查询优化。
在创建分布式查询计划时会利用数据位置 SPI 来生成表内容的逻辑切片。切片是任务分配和并行的最小单位。
分布式查询计划是简单查询计划的一个扩展,它包含一个或多个 Stage。简单查询计划被切分为多个计划片段(plan fragment)。Stage 是在运行时的计划片段,它包含对应计划片段所描述的所有任务。
一个任务处理数据的单位是切片。切片代表一个工作节点可以抽取并处理的一段底层数据,它是并行和任务分配的单位。连接器所执行的特定数据操作取决于底层的数据源。例如,Hive 连接器用文件的路径、读取偏移量和长度来描述切片信息,这些信息指明了所要处理文件的区域。
要处理一条查询,协调器首先根据来自连接器的元数据创建切片列表。使用该切片列表,协调器开始在工作节点上调度任务,以获取其中的数据。在查询执行期间,协调器跟踪所有可用于处理的切片和任务在工作节点上执行的位置。一些任务完成了处理,并产生了很多供下游处理的切片,协调器就会继续调度更多的任务来处理它们,直到没有待处理的切片为止。
一旦工作节点处理完了所有切片,全部数据就可用了。此时协调器会将结果返回给客户端。
优化规则
谓词下推
这一规则将过滤条件(Filter)移动到尽可能接近数据源的位置,因此,数据量在查询开始后尽可能早地开始缩减。
Cross Join消除
对表重新排序,把一些Cross Join变成Inner Join。
TopN
把ORDER BY 和 LIMIT 合并成一个 TopN 计划节点。
局部聚合
注:如果诸如count之类的聚合函数可以下推就好了。
实现规则
Lateral Join去关联化
Lateral Join 可以通过如下方式实现:使用 for 循环迭代一个数据集中的所有行,并对每一行执行另一次的查询。使用这样的实现方法是可能的,但并非 Presto 处理类似场景所采取的方法。相反,Presto 将子查询去关联化(decorrelate),它将所有的相关条件拉取上来并形成一个标准的 Left Join。
Semi-join(IN)去关联化
注:作用应该是避免多次查询
基于代价的优化器
Presto在决策时不但基于查询本身的形状,而且更重要的是,它们也将查询数据的形状考虑在内。这就是 Presto 先进的基于代价的优化器(cost-based optimizer,CBO)所做的工作。
CPU 时间、内存需求和网络带宽的使用都是构成查询执行时间的三个维度,这些维度组成了 Presto 的代价。
Join的代价
使用相等条件(=)Join 两个表时,Presto 可以实现 Hash Join 的扩展版算法。其中一个表称为构建侧,这个表的内容以 Join 条件使用的列作为键,构建一个散列查询表。另一个表称为探测侧,一旦散列查找表构建完成,就会使用探测侧表的行去构建侧的散列表中以常数时间查找匹配的行。
默认情况下,Presto 会使用三层散列以尽可能地并行处理。节点级别,线程级别,数据分区。
构建侧的数据一直存放在内存中。
表统计信息
连接器也可以提供表和列的统计信息:表中行的数量;列中不同值的数量(基数);列中 NULL 值所占的比例;列的最大值和最小值;列的平均数据大小。
有了对 Join 表中行数的估计以及可选列的平均数据长度信息,CBO就能够对表从大到小排序,更小数据量的表放在构建侧。
过滤统计信息
利用列中不同值的数量,估算过滤过的数据集大小。
分区表的统计信息
使用 Hive连接器链接的 Hive/HDFS 数据仓库可能将数据组织成分区表。
广播Join和分布式Join
在广播 Join 策略中,Join 的构建侧广播到并行执行 Join 的所有工作节点上。适用于数据量小的情况。
在分布式 Join 策略中,构建侧和探测侧的输入数据都需要在集群中重分布,从而使工作节点可以并行执行 Join。与广播 Join 策略不同,分布式 Join 策略下,每个工作节点接收到的都是数据集中独一无二的一部分,而不是数据的相同副本。适用于数据量大的情况。
注:统计信息决定了Join表的顺序。数据量的大小决定了使用广播Join还是分布式Join。
连接器
连接器将底层数据源(如 RDBMS、对象存储或键值存储)的查询和存储概念翻译成 SQL 和 Presto 中的表、列、行和数据类型的概念。
可以像看待数据库的驱动程序一样看待连接器。它将用户的输入转化为底层数据库可以执行的操作。每个连接器都实现了 Presto 服务提供者接口(service providerinterface,SPI)。这让你能够用同一套 SQL 工具操作任意连接器暴露的底层数据源,从而使 Presto 成为一个 SQL-on-Anything 的系统。
RDBMS连接器
查询下推
目前,Presto 连接器的 SPI 限制只能将过滤和列投影下推。
如果想将额外的处理下推到底层 RDBMS 源,可以使用视图来实现。比如把count下推。
并行性和并发性
当从同一个 RDBMS 中访问多个表时,对查询中的每个表都会创建一个 JDBC 连接。并行运行,返回结果,然后在Presto 中执行连接。
Presto TPC-H和TPC-DS连接器
这些连接器可用于测试 Presto 的能力和查询语法,无须配置外部数据源的访问。
Hive连接器
Hive
Hive 的元数据描述了存储在 HDFS 中的数据如何映射到 schema、表和列中,并通过 SQL 进行查询。这些元数据信息保存在 MySQL 或 PostgreSQL 等数据库中,可以通过 Hive Metastore 服务(HMS)进行访问。
Hive 运行时提供了类似 SQL 的查询语言和分布式执行层来执行查询。Hive 运行时将查询翻译成一组可以在 Hadoop 集群上运行的 MapReduce 程序。
Hive连接器
Presto 的 Hive 连接器允许你连接到 HDFS 对象存储集群。它利用 HMS 中的元数据,查询和处理存储在 HDFS 中的数据。
在架构上,Hive 连接器与 RBDMS 和其他连接器有一点不同。因为它根本不使用Hive 引擎本身,所以不能将 SQL 处理下推到 Hive 中。相反,Hive 连接器只是使用 HMS 中的元数据,并使用 Hadoop 项目提供的 HDFS 客户端直接访问 HDFS上的数据。它还假定数据以 Hive 表格式保存在分布式存储中。
内部表与外部表
内部表由Presto管理数据,外部表不由Presto管理数据。不管内部表还是外部表,都是由HMS管理元数据。
分区数据
一个表的数据,不管是内部的还是外部的,都是以一个或多个文件的形式存储在一个目录中。数据分区是这一点的延伸,它将逻辑表横向划分为小块数据,称为分区。
使用分区可以改变表的布局构建方式。使用分区表在表目录中添加了额外的子目录。在下面的例子中,可以看到由分区键view_date定义的目录结构:
/page_views/view_date=2021-07-29/...
分区可以提高查询性能,特别是当你的数据规模越来越大时。当提交此查询时,Presto 会识别 WHERE 子句中的分区列,只读取需要的分区。
非关系数据源
Presto JMX连接器
黑洞连接器
因为它实际上不写入任何内容,所以你可以用它来衡量从其他 catalog 中读取数据的性能。
内存连接器
使用内存连接器对查询测试或临时存储非常有用。
在Presto中使用SQL
Presto语句
SHOW STATS FOR table_name 显示某个表中的数据规模和数量等统计信息。
EXPLAIN 生成查询计划,并详细列出各个步骤。
Presto系统表
Presto 系统表不需要配置 catalog 文件,所有的 schema 和表都在 systemcatalog 中自动提供。
为了进行查询调优,表 system.runtime.queries 和 system.runtime.tasks 是最有用的。
Information Schema
Information Schema 是 SQL 标准的一部分,并在 Presto 中作为一组视图,提供了关于 catalog 中的 schema、表、列、视图和其他对象的元数据。
SELECT语句的WITH子句
WITH 子句用于在单个查询中定义一个内联视图。这通常可以使查询更可读,因为查询可能需要多次包含相同的嵌套查询。
安全
在典型的 Presto 集群部署和使用中,可以考虑保障几个方面的安全:
- 用户客户端与 Presto 协调器之间的数据传输;
- Presto 集群内协调器和工作节点之间的数据传输;
- Presto 集群和按 catalog 配置的每个数据源之间的数据传输;
- 访问每个数据源内的具体数据。
将Presto与其他工具集成
- 使用Apache Superset进行查询、可视化和更多操作
- 使用RubiX提高性能
- 使用Apache Airflow的工作流
- 嵌入式Presto示例:Amazon Athena
- Starburst企业版Presto
生产环境中的Presto
使用Presto Web UI监控
Presto SQL查询调优
你需要鉴别是某个查询本身存在性能问题,还是具有某些相似属性的多个查询有性能问题。
在检查慢查询时,你应该首先检查查询使用到的表是否有数据统计信息。
SQL 中 Join 是成本最高的操作之一,在进行查询性能调优时,你应该重点关注Join。你可以在查询上使用 EXPLAIN 命令来确定 Join 顺序
内存管理
想要正确地配置和管理 Presto 集群的内存并不容易。许多持续变化的因素会影响内存需求:工作节点的数量;协调器和工作节点的内存;数据源的数量和类型;所执行的查询的特性;用户的数量。
任务并发性
任务工作线程数,任务的算子并发数。
工作节点调度
通常有 3个常见的配置可以调整:每个任务的切片数;每个节点的切片数;本地调度策略。
网络数据交换
并发性,缓冲区大小。
JVM调优
资源组
资源组(resource group)是 Presto 中用于限制系统资源使用的一个非常有用的概念。资源组的配置包含两个方面:资源组属性和选择器规则。
资源组是一系列定义可用集群资源的命名属性,你可以认为一个资源组是集群中与其他资源组隔离的一部分资源。资源组由 CPU 和内存限制、并发数限制、队列优先级和队列中查询的优先级权重等定义。
真实世界的案例
部署和运行时平台
物理机组成的集群越来越少见。虚拟机是目前最常用的平台。容器的使用正逐渐成为标准,很可能取代虚拟机的位置。
集群规模
在现实世界中大规模使用 Presto 的情况大多数是使用多集群部署。
Lyft:超过 400 个节点,每个集群 100~150 个节点。数据超过 20PB。大约 1500 名用户。每天超过 100 000 条查询,每月超过 1 500 000 条查询。
