Presto是一个分布式SQL查询引擎,用于查询分布在一个或多个不同数据源中的大数据集,完整安装包括一个Coordinator或多个Worker。由客户端提交查询,从Presto命令行CLI提交到Coordinator,Coordinator进行解析,分析执行查询计划,然后分发处理队列到Worker。

Presto特点
- Presto是完全基于内存的分布式大数据查询引擎,所有查询和计算都在内存中执行
- Presto的输入是SQL语句,输出是具体的SQL执行结果
- Presto可以对接不同的数据源,例如MySQL、Hive等
- Presto可以对SQL的处查询过程进行优化,包括SQL本身的执行计划优化,以及用分布式查询提高并发等
- Presto不是数据库,并不能处理在线事务
基本概念
Presto服务进程
Presto集群中一共有两种服务器进程:Coordinator服务进程和Worker服务进程,其中Coordinator服务进程的主要作用是:接收查询请求、解析查询语句、生成查询执行计划、任务调度和Worker管理。而Worker服务进程则执行被分解后的查询执行任务:Task
Coordinator
作用:
- 对外负责管理集群与客户端的连接,并接收客户端查询请求
- 进行SQL的语法解析、查询计划生成和优化,并进行查询任务的调度
- 集群的管理节点,内置了discovery server,跟踪Worker节点的状态
部署情况:一般作为单独节点部署在集群中,如测试需求,可以与Worker节点部署一个节点
通信方式:使用Restful接口与客户端、Workers进行交互
Worker
作用:集群的工作节点,用于执行被分解后的查询任务(Task)及处理数据
部署情况:一般集群中部署多个worker节点
通信方式:使用Restful接口与Coordinator、其他Workers进行交互
交互关系
状态管理:Workers每隔一段时间会向Coordinator发送Restful心跳,告知Coordinator的Discover Server状态
数据处理:
- Worker:负责从connectors拉取数据,并与其他workers进行中间数据的交互处理
- Coordinator:负责从Workers拉取结果,并将最终结果返回给客户端 Coordinator接收到客户端查询后,从存活的Workers列表中选出合适的Workers进行运行Task
Presto模型
Presto可以通过多种不同类型的Connector访问多种数据源,目前支持的Connector包括:Hive、JMX、MySQL、Cassandra、PostgreSQL以及Kafka。
Connector
作用:Presto通过connector可以访问多种不同的数据源,connector相当于数据库访问的驱动 每种connector通过实现Presto的SPI接口实现数据源的标准接入
通过connector访问数据源
- 在$PRESTO_HOME/etc/catalog/下创建配置文件:example.properties(后缀必须为properties)
- 设置属性connector.name,必选属性,catalog manager通过该配置属性创建访问相应数据源的connector
- 支持使用多个catalog使用相同的connector去访问两个相似的数据源,例如,可以再一个presto集群中配置两个catalog(都是使用Hive connector),用于访问两个Hive集群
Catalog
类似于MySQL中的一个数据库实例,Catalog可以包含多个schema,并且通过使用指定的connector访问指定的数据源,例如,通过配置Hive catalog来访问Hive数据源
Schema
类似于MySQL中的Database,用于管理表,一个catalog和一个schema可以唯一确定一组可查询的表集合
Table
与传统数据库中的Table含义是一样的,从数据源到表映射由connector指定
Presto查询执行模型
Presto在执行SQL语句时,将SQL语句解析为相应的查询,并在分布式集群中执行这些查询
1. Statement
Statement语句,其实就是输入的SQL语句,在Presto中语句(Statement)和查询(Query)是不同的概念,当Presto执行输入的SQL语句时,会根据SQL语句生成查询执行计划,进而生成可以执行的查询(Query),查询代表的是分布到所有的Worker之间执行的实际查询操作
2. Query
Query即查询执行,一个查询执行代表可以在Presto集群中运行的查询,是由运行在各个Worker上且各自之间相互关联的阶段(Stage)组成的。
一个查询执行由Stage、Task、Driver、Split、Operator和DataSource组成,这些组件间通过内部联系共同组成了一个查询执行,从而得到SQL语句表述的查询,并得到相应的结果集。
3. Stage
Stage即查询执行阶段,当Presto运行Query时,Presto会将一个Query拆分成具有层级关系的多个Stage,一个Stage就代表查询执行计划的一部分,
通常情况下,Stage之间是树状的层级结构,每个Query都有一个Root Stage,该Stage用于聚集所有其他Stage的输出数据,并将最终的数据反馈给终端用户,Stage并不会在集群中实际执行,它只是Coordinator用于对查询执行计划进行管理和建模的逻辑概念。每个Stage(除了Single Stage和Source Stage)都会有输入和输出,都会从上游Stage读取数据,然后将产生结果输出给下游Stage,Source Stage没有上游Stage,它从Connector获取数据,Single Stage没有下游Stage,它的结果直接输出给Coordinator,并由Coordinator输出给终端用户。
Stage类型:
- Coordinator_only:这种类型的Stage用于执行DDL或者DML语句中最终的表结构创建或者更改
- Single:这种类型的Stage用于聚合子Stage的数据输出数据,并将最终数据输出给终端用户
- Fixed:这种类型的Stage用于接收其子Stage产生的数据并在集群中对这些数据进行分布式的聚合或者分组计算
- Source:这种类型的Stage用于直接连接数据源,从数据源读取数据,在读取数据的时候,该阶段也会根据Presto对查询执行计划的优化完成相关的断言下发(Predicate PushDown)和条件多虑等。
按照数据的流向,越靠近数据源的Stage越处于上游,越远离数据源的Stage越处于下游
4. Exchange
Presto的Stage是通过Exchange来连接另一个Stage的,Exchange用于完成上下游的Stage之间的数据交换。
5. Task
Stage在逻辑上又被分为一系列的Task,这些Task则是需要实际运行在Presto的各个Worker节点上的。
在Presto集群中,一个查询执行被分解成具有层级关系的一系列的Stage,一个Stage又被拆分为一系列的Task,每个Task处理一个或者多个Split。每个Task都有对应的输入和输出,一个Stage被分解为多个Task,从而可以并行地执行一个Stage,Task也采用了相同的机制:一个Task也可以分解为一个或多个Driver,从而并行地执行一个Task
6. Driver
一个Task包含一个或者多个Driver,一个Driver其实就是作用于一个Split的一系列Operator的集合。Driver是Presto架构最底层的并行处理单元,每个Driver都有一个输入和一个输出。
7. Operator
一个Operator代表对一个Split的一种操作,例如过滤、加权、转换等。一个Operator依次读取一个Split中的数据,将Operator所代表的计算和操作作用于Split的数据上,并产生输出,每个Operator均会以Page为最小处理单位分别读取输入数据和产生输出数据,Operator每次只会读取一个Page对象,相应地,每次也只会产生一个Page对象。
8. Split
Split即分片,一个分片其实就是一个大的数据集中的一个小的子集,而Driver则是作用于一个分片上的一系列操作的集合,而每个节点上运行的Task,又包含多个Driver,从而一个Task可以处理多个Split,其中每一种操作均由一个Operator表示。
9. Page
Page是Presto中处理的最小数据单元,一个PAge对象包含多个Block对象,而每个Block对象是一个字节数组,存储一个字段的若干行,多个Block横切的一行是真实的一行数据,一个Page最大为1MB,最多16x1024行数据。
在Presto中一次查询执行会被分解为多个Stage,Stage与Stage之间是有前后依赖关系的。每个Stage内部又会进一步分解为多个Task,属于每个Stage的Task被均分在每个Worker上并行执行,在每个Task内部又会被分解为多个Driver,每个Driver负责处理一个Split,而且每个Driver由一系列前后相连的Operator组成,这里的每个Operator都代表针对于一个Split的一种操作。
参考:
prestodb.io/overview.ht…
prestodb.jd.com/
zhuanlan.zhihu.com/p/111053544