facebook Presto SQL分析引擎——本质上和spark无异,分解stage,task,MR计算
Presto 是由 Facebook 开源的大数据分布式 SQL 查询引擎,适用于交互式分析查询,可支持众多的数据源,包括 HDFS,RDBMS,KAFKA 等,而且提供了非常友好的接口开发数据源连接器。
介绍
Presto是一个运行在多台服务器上的分布式系统。 完整安装包括一个coordinator和多个worker。 由客户端提交查询,从Presto命令行CLI提交到coordinator。 coordinator进行解析,分析并执行查询计划,然后分发处理队列到worker。
完全基于内存的并行计算
查询的并行执行流程
Presto SQL的执行流程如下图所示
- Cli通过HTTP协议提交SQL查询之后,查询请求封装成一个SqlQueryExecution对象交给Coordinator的SqlQueryManager#queryExecutor线程池去执行
- 每个SqlQueryExecution线程(图中Q-X线程)启动后对查询请求的SQL进行语法解析和优化并最终生成多个Stage的SqlStageExecution任务,每个SqlStageExecution任务仍然交给同样的线程池去执行
- 每个SqlStageExecution线程(图中S-X线程)启动后每个Stage的任务按PlanDistribution属性构造一个或者多个RemoteTask通过HTTP协议分配给远端的Worker节点执行
- Worker节点接收到RemoteTask请求之后,启动一个SqlTaskExecution线程(图中T-X线程)将这个任务的每个Split包装成一个PrioritizedSplitRunner任务(图中SR-X)交给Worker节点的TaskExecutor#executor线程池去执行
上面的执行计划实际执行效果如下图所示。
- Coordinator通过HTTP协议调用Worker节点的 /v1/task 接口将执行计划分配给所有Worker节点(图中蓝色箭头)
- SubPlan1的每个节点读取一个Split的数据并过滤后将数据分发给每个SubPlan0节点进行Join操作和Partial Aggr操作
- SubPlan1的每个节点计算完成后按GroupBy Key的Hash值将数据分发到不同的SubPlan2节点
- 所有SubPlan2节点计算完成后将数据分发到SubPlan3节点
- SubPlan3节点计算完成后通知Coordinator结束查询,并将数据发送给Coordinator
源数据的并行读取
在上面的执行计划中SubPlan1和SubPlan0都是Source节点,其实它们读取HDFS文件数据的方式就是调用的HDFS InputSplit API,然后每个InputSplit分配一个Worker节点去执行,每个Worker节点分配的InputSplit数目上限是参数可配置的,Config中的query.max-pending-splits-per-node参数配置,默认是100。
分布式的Hash聚合
上面的执行计划在SubPlan0中会进行一次Partial的聚合计算,计算每个Worker节点读取的部分数据的部分聚合结果,然后SubPlan0的输出会按照group by字段的Hash值分配不同的计算节点,最后SubPlan3合并所有结果并输出
流水线
数据模型
Presto中处理的最小数据单元是一个Page对象,Page对象的数据结构如下图所示。一个Page对象包含多个Block对象,每个Block对象是一个字节数组,存储一个字段的若干行。多个Block横切的一行是真实的一行数据。一个Page最大1MB,最多16*1024行数据。
节点内部流水线计算
下图是一个Worker节点内部的计算流程图,左侧是任务的执行流程图。
Worker节点将最细粒度的任务封装成一个PrioritizedSplitRunner对象,放入pending split优先级队列中。每个
Worker节点启动一定数目的线程进行计算,线程数task.shard.max-threads=availableProcessors() * 4,在config中配置。
每个空闲的线程从队列中取出一个PrioritizedSplitRunner对象执行,如果执行完成一个周期,超过最大执行时间1秒钟,判断任务是否执行完成,如果完成,从allSplits队列中删除,如果没有,则放回pendingSplits队列中。
每个任务的执行流程如下图右侧,依次遍历所有Operator,尝试从上一个Operator取一个Page对象,如果取得的Page不为空,交给下一个Operator执行。
节点间流水线计算
下图是ExchangeOperator的执行流程图,ExchangeOperator为每一个Split启动一个HttpPageBufferClient对象,主动向上一个Stage的Worker节点拉数据,数据的最小单位也是一个Page对象,取到数据后放入Pages队列中
本地化计算
Presto在选择Source任务计算节点的时候,对于每一个Split,按下面的策略选择一些minCandidates
- 优先选择与Split同一个Host的Worker节点
- 如果节点不够优先选择与Split同一个Rack的Worker节点
- 如果节点还不够随机选择其他Rack的节点
对于所有Candidate节点,选择assignedSplits最少的节点。
动态编译执行计划
Presto会将执行计划中的ScanFilterAndProjectOperator和FilterAndProjectOperator动态编译为Byte Code,并交给JIT去编译为native代码。Presto也使用了Google Guava提供的LoadingCache缓存生成的Byte Code。
上面的两段代码片段中,第一段为没有动态编译前的代码,第二段代码为动态编译生成的Byte Code反编译之后还原的优化代
码,我们看到这里采用了循环展开的优化方法。
循环展开最常用来降低循环开销,为具有多个功能单元的处理器提供指令级并行。也有利于指令流水线的调度。
小心使用内存和数据结构
使用Slice进行内存操作,Slice使用Unsafe#copyMemory实现了高效的内存拷贝,Slice仓库参考:https://github.com/airlift/slice
Facebook工程师在另一篇介绍ORCFile优化的文章中也提到使用Slice将ORCFile的写性能提高了20%~30%,参考:https://code.facebook.com/posts/229861827208629/scaling-the-facebook-data-warehouse-to-300-pb/
类BlinkDB的近似查询
为了加快avg、count distinct、percentile等聚合函数的查询速度,Presto团队与BlinkDB作者之一Sameer Agarwal合作引入了一些近似查询函数approx_avg、approx_distinct、approx_percentile。approx_distinct使用HyperLogLog Counting算法实现。
GC控制
Presto团队在使用hotspot java7时发现了一个JIT的BUG,当代码缓存快要达到上限时,JIT可能会停止工作,从而无法将使用频率高的代码动态编译为native代码。
Presto团队使用了一个比较Hack的方法去解决这个问题,增加一个线程在代码缓存达到70%以上时进行显式GC,使得已经加载的Class从perm中移除,避免JIT无法正常工作的BUG。
facebook Presto SQL分析引擎——本质上和spark无异,分解stage,task,MR计算的更多相关文章
- InfluxDB存储引擎Time Structured Merge Tree——本质上和LSM无异,只是结合了列存储压缩,其中引入fb的float压缩,字串字典压缩等
The New InfluxDB Storage Engine: Time Structured Merge Tree by Paul Dix | Oct 7, 2015 | InfluxDB | 0 ...
- 软件-分布式:Kylin (apache开源分布式分析引擎软件)
ylbtech-软件-分布式:Kylin (apache开源分布式分析引擎软件) Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以 ...
- APACHE KYLIN™ 概览(分布式分析引擎)
Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop/Spark之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献至开源社区.它能 ...
- 探究Presto SQL引擎(3)-代码生成
vivo 互联网服务器团队- Shuai Guangying 探究Presto SQL引擎 系列:第1篇<探究Presto SQL引擎(1)-巧用Antlr>介绍了Antlr的基本用法 ...
- 实时查询引擎 - Facebook Presto 介绍与应用
1. Presto 是什么 Facebook presto是什么,继Facebook创建了HIVE神器后的又一以SQL语言作为接口的分布式实时查询引擎,可以对PB级的数据进行快速的交互式查询.它支 ...
- 探究Presto SQL引擎(4)-统计计数
作者:vivo互联网用户运营开发团队 - Shuai Guangying 本篇文章介绍了统计计数的基本原理以及Presto的实现思路,精确统计和近似统计的细节及各种优缺点,并给出了统计计数在具体业务 ...
- 用scala实现一个sql执行引擎-(上)
前言 在实时计算中,通常是从队列中收集原始数据,这种原始数据在内存中通常是一个java bean,把数据收集过来以后,通常会把数据落地到数据库,供后面的ETL使用.举个一个简单的例子,对一个游戏来说, ...
- 详细分析 Java 中实现多线程的方法有几种?(从本质上出发)
详细分析 Java 中实现多线程的方法有几种?(从本质上出发) 正确的说法(从本质上出发) 实现多线程的官方正确方法: 2 种. Oracle 官网的文档说明 方法小结 方法一: 实现 Runnabl ...
- explain慢SQL分析解释
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是 如何处理你的SQL语句的.分析你的查询语句或是表结构的性能瓶颈. 使用方式:Explain+SQL语句 执行计划包含的信 ...
随机推荐
- css position是前端的你了解多少?
此文根据Steven Bradley的<How Well Do You Understand CSS Positioning?>所译,整个译文带有我自己的理解与思想,如果译得不好或不对之处 ...
- 五、PL/SQL循环、游标、函数和过程
--PL/SQL基础知识学习 --一.PL/SQL语句块,基础语法格式 DECLARE --变量声明列表 info varchar(25); --变量声明 stu_unm integer := 15; ...
- Leetcode 300.最长上升子序列
最长上升子序列 给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的 ...
- sql通配符+sql中查询条件包含下划线等通配符的写法
一.SQL 通配符 在搜索数据库中的数据时,SQL 通配符可以替代一个或多个字符. SQL 通配符必须与 LIKE 运算符一起使用. 在 SQL 中,可使用以下通配符: 通配符 描述 % 替代一个或多 ...
- [Docker]容器的隔离与限制
1.Docker事实 1)容器技术的兴起源于Pass技术的普及 2)Docker公司发布的Docker项目具有里程碑式的意义 3)Docker项目通过容器镜像解决了应用打包这个根本性难题 4)容器本身 ...
- 【HDOJ6342】Expression in Memories(模拟)
题意: 给定一个由0123456789+* ?组成的表达式,其中?可以被改为任意其它字符,问修改问号后是否有方案使得表达式合法 len<=5e2,sumlen<=1e5 思路: #incl ...
- ibatis中的xml配置文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE sqlMap PUBLIC "-/ ...
- 洛谷 P4720 【模板】扩展 / 卢卡斯 模板题
扩展卢卡斯定理 : https://www.luogu.org/problemnew/show/P4720 卢卡斯定理:https://www.luogu.org/problemnew/show/P3 ...
- eclipse菜单字体乱码的解决
方法一: 这个跟活动控制台代码页有关. 如果要更改为 UTF-8,则需要运行 chcp 命令: chcp 65001 有时新安装的系统可能在运行一些中文软件时显示错乱,可通过控制面板修改系统区域来管理 ...
- 使用Spring定时任务并且通过AOP监控任务执行情况
原文:http://www.open-open.com/code/view/1426250803279 本文讲的是通过Spring注解的方式实现任务调度.只要引入了spring-context包就能够 ...