Presto:分布式 SQL 查询引擎

Presto 是什么?

Presto™ (PrestoDB) is an open source distributed SQL query engine for running interactive analytic queries against data sources of all sizes ranging from gigabytes to petabytes.

Presto™ (PrestoSQL) is a high performance, distributed SQL query engine for big data.

下文将详细介绍二者的区别

基本概念

组件

Coordinator

 负责管理 Worker 和 MetaStore 节点,以及接受客户端查询请求,并进行 SQL 的语法解析(Parser)、执行计划生成与优化(Planner)和查询任务的调度(Scheduler)

Coordinator 通过 RESTful 接口与 Client 和 Worker 交互

Worker

 负责具体的查询计算和数据读写

Discovery Server

 负责发现集群的各个节点,用于节点间心跳监控

一般 Discovery Server 混布在 Coordinator 节点上,也支持单独部署

数据源

Connector

 负责访问不同的数据源,相当于访问数据库的驱动

Catalog

 负责记录 Schema 信息和 DataSource 的引用。Presto 中一个完整的表名通过 <Catalog>.<Schema>.<Table> 组合表示。例如 hive.test_data.test,则表示:

  • Catalog 为 hive
  • Schema 为 test_data
  • Table 为 test

Schema

 一种组织 Table 的方式

Table

 等同于关系型数据库中表的概念

查询模型

Statement

 兼容 ANSI 标准的 SQL 字符串

Query

 当 Presto 解析一条 SQL 语句时,会将其转换为 Query,并创建一个分布式 Query 执行计划

整个查询过程涉及 Stage、Task、Split、Connector 和 DataSource 等组件的协同工作

Stage

 当 Presto 执行查询时,会进一步分为多个 Stage 阶段来执行

Task

 Stage 包含了一系列的 Task,而 Task 才是真正在 Worker 之上被执行的逻辑

Split

 Split 主要是为了拆分大规模数据集,以便 Task 在此之上执行

Driver

 Driver 是一系列运算实例,可以理解为是内存中的一组物理运算符

Task 可以包含一个或者多个并行的 Driver

Operator

 Operator 可以消费(Consume)、转换(Transform)和生产(Produce)数据。例如,一个 Table Scan 从一个 Connector 中 fetch 数据,并生产数据以供给 Operator 消费

Exchange

 Exchanage 负责在 Presto 的节点之间,传输一个 Query 的不同 Stage 的数据。Task 可以生产数据到一个 output 缓存区,也可以通过 Exchange 客户端消费其他 Task 生产的数据

优缺点

优势

  • Ad Hoc(即席查询,秒级或分钟级的查询响应)
  • 比 Hive 快 10x 倍
    • 完全基于内存的并行计算
    • 流水线
    • 本地化计算
    • 动态编译执行计划
    • 内存规划
    • 近似查询(类似于 BlinkDB
    • GC 控制
  • 支持多种数据源(Hive、DruidKafka、MySQL、MongoDB、RedisJMXORC 等)
  • Client 支持多种编程语言(JavaPython、Ruby、PHP、Node.js 等)
  • 支持 JDBC / ODBC 连接
  • 支持 Kerberos 认证
  • 支持查询 LZO 压缩的数据
  • ANSI SQL(窗口函数、Join、聚合、复杂查询等)
Ad Hoc(拉丁短语,英语直译为 for this)即席查询,用户根据实际需求,灵活地选择查询条件,系统生成相应的统计报表。与普通应用查询不同的是,普通应用查询需要通过编程定制开发
即席(jí xí),表示入席、就位、当场等含义
ANSI(American National Standards Institute)美国国家标准学会

劣势

  • 不支持 SQL 的隐式类型转换,而 Hive 支持
  • 不支持容错
    查询请求会分发到多个 Worker 上,当任意一个 Worker 执行失败,Master 会感知到,并认为整个查询请求失败了。并且 Presto 并没有重试机制,所以需要业务端完成重试
Presto 属于强数据类型,并不支持类型的隐式转换,所以无法进行不同数据类型之间的比较,例如 '2' > 1 等。不过,在对应算子中增加新的语义行为即可支持。下文将介绍具体的编码过程

架构

架构图

Presto Architecture

(图片来源:medium.com™)

Presto Architecture with SQL

(图片来源:slideshare.net™)
从架构图可以看出,Presto 采用的是经典的 Master-Slave 模型

SQL 执行流程图

Presto SQL Execute

(图片来源:cnblogs.com™)

Connector 交互图

Presto Connector

(图片来源:slideshare.net™)

交互时序图

sequenceDiagram

participant Client
participant Coordinator
participant Worker
participant Connector
participant Discovery Server

Client ->>+ Coordinator : query
Coordinator ->>+ Worker : choose workers
Worker ->>- Coordinator : return worker list
Coordinator ->>+ Worker : send task
Worker ->>+ Connector : load data
Connector ->>- Worker : return data
Worker ->> Worker : execute task
Worker ->>- Coordinator : return result
Coordinator ->>- Client : return result
loop regularly
  Coordinator -->> Discovery Server : heart beat
  Worker -->> Discovery Server : heart beat
end
其中,与 Discovery Server 的心跳并不参与到查询过程中

MPP

 Presto 采用 MPP(Massively Parallel Processing)大规模并行处理架构,来解决大量数据分析的场景。该架构的主要特征,如下:

  • 任务并行执行
  • 分布式计算
  • Shared Nothing
  • 横向扩展
  • 数据分布式存储(本地化)

SPI

 Presto 采用 SPIService Provider Interface)服务提供发现机制,来插件化地支持多种数据源,以实现联邦查询(Federation Query,指能够通过一条 SQL 查询,对处于完全不同的系统中的不同的数据库和模式,进行引用和使用)

比对

Presto vs Apache Hive

优势比较

Presto Apache Hive
场景特征 交互式查询 高吞吐
Join 一个较大的事实表 + 多个较小的维度表 事实表 + 事实表
窗口函数 支持 支持
SQL 标准化 ANSI SQL HiveQL

架构比较

Presto vs Hive on Architecture

(图片来源:treasuredata.com™)

Presto vs Amazon Athena

 本质上,Amazon Athena(雅典娜)是一款完全支持标准 SQL 的 Presto

PrestoDB vs PrestoSQL

PrestoDB PrestoSQL
开源时间 2012 2018
研发主力 Facebook Martin、Dain 和 David
通讯模式 支持 RESTful 和二进制 仅支持 RESTful
查询下推 支持 支持
技术输出 博客 博客 + 视频 + 书籍
Connector 数量 24 30
社区活跃度 相对不活跃 相对活跃
合并 PR 数量 90 205
解决 Issues 数量 52 81
改动的代码行数 20088 63297
上表中 PR、Issues 和代码行数的统计时间范围是最近一个月的

踩过的坑

不支持类型的隐式转换

描述

 原本只支持数值类型之间的比较,例如 2 > 1

1
2
3
4
5
6
@ScalarOperator(GREATER_THAN)
@SqlType(StandardTypes.BOOLEAN)
public static boolean greaterThan(@SqlType(StandardTypes.BIGINT) long left, @SqlType(StandardTypes.BIGINT) long right)
{
return left > right;
}

解决

 增加以下方法,以支持字符串与数值之间的比较,例如 '2' > 1

1
2
3
4
5
6
@ScalarOperator(GREATER_THAN)
@SqlType(StandardTypes.BOOLEAN)
public static boolean greaterThan(@SqlType(StandardTypes.VARCHAR) String left, @SqlType(StandardTypes.BIGINT) long right)
{
return Long.parseLong(left) > right;
}
当然也可以显示地调用 cast 函数进行类型转换

社区发展

Star 趋势

Presto Star History

(图片来源:star-history.t9t.io™ 官网)

个人贡献

 详见:《如何成为 Apache 的 PMC

资料

Doc

Github

Blog

Book

欢迎加入我们的技术群,一起交流学习

群名称 群号
人工智能(高级)
人工智能(进阶)
BigData
算法

欢迎关注我的其它发布渠道