Presto

前言

1 了解计算引擎的发展史

  • 第一代计算引擎:基于磁盘的分布式计算
    • MapReduce
    • 优点:对硬件要求不高,开发简单,成本较低
    • 缺点:灵活性差,性能较差
  • 第二代计算引擎:基于DAG的分布式计算 Hive => 默认引擎调整为Tez
    • Tez
    • 优点:基于MR引入DAG设计,灵活性高,提升了MR的性能 => 减少了落盘次数
    • 缺点:性能不足以满足需求,底层还是MR
  • 第三代计算引擎:基于内存的分布式计算 => 离线计算
    • Spark、Impala、Presto => 写SQL(Impala > Presto > Spark)
    • 优点:基于内存式计算,性能较高,支持SQL接口
    • 缺点:内存消耗较高,成本较高
  • 第四代计算引擎:基于实时数据流的分布式计算 => 实时计算
    • Storm、Flink
    • 优点:实时数据处理,性能最高,数据价值可以实现最大化
    • 缺点:目前技术功能和接口不是非常成熟,还需要不断完善

2 Presto

1 功能及应用常场景

Presto是一个Facebook技术团队开源的分布式SQL查询引擎,用于代替Hive,适用于交互式分析查询,数据量支持GB到PB
功能:实现基于内存的分布式数据计算引擎
特点:性能高,接口丰富

高性能的数据查询,数据处理全部基于内存来实现
清晰的架构,是一个能够独立运行的系统,不依赖于任何其他外部系统
简单的数据结构,列式存储,逻辑行,大部分数据都可以轻易的转化成presto所需要的这种数据结构
丰富的插件接口,完美对接外部存储系统,或者添加自定义的函数

适合的场景:大数据的交互式分析查询:秒级的查询时延

AWS上Athena作为一个大数据商业服务提供给商业付费客户,底层就是Presto服务
京东精准营销平台中JD-Presto作为大数据Ad-Hoc计算平台,极大提升了采销部门进行精准营销活动的效果和效率
美团在2014年在Hadoop集群上搭建了Presto来服务于公司内部的分析师、PM、工程师

不适合的场景

OLTP:Presto不是数据库,没有存储结构,只是一个基于存储之上的一个分布式查询工具
数据分析引擎:Presto的数据都在内存中做计算,复杂的分析会导致OOM【out of memory】

小结

Presto是第三代计算引擎,Facebook在2012年研发,免费开源
Presto内存计算适合海量数据分析(秒级查询),不适合做数据库以及超复杂数据分析
优点:内存计算提高性能,可以连接多方数据库

2 分布式架构

内存型 + 分布式计算Presto

3 Presto的常用语法

语法:https://prestodb.io/docs/current/

Presto是通用型计算引擎:数据源是多样化(支持MySQL、支持Hive、支持Oracle)
法设计满足大多数数据库都支持的语法

数据类型:

  • tinyint、smallint、integer、 bigint、double、decimal
  • varchar、 char、varbinary、json(注意:Presto中没有string类型
  • date、time、 timestamp
  • array, map
  • boolean

Presto有些数据类型无法兼容Hive!!!
虽然Presto可以替代Hive,但是在实际工作中,两者一般都要配合在一起使用:
Hive负责数据库、数据表构建(DDL、DML)
Presto(DQL)

DDL语法:支持,但是一般都不在Presto中使用
数据库操作

-- 建库
CREATE SCHEMA [ IF NOT EXISTS ] schema_name
CREATE SCHEMA IF NOT EXISTS db_test01;
-- 列举
SHOW SCHEMAS
-- 删库
DROP SCHEMA [ IF EXISTS ] schema_name
DROP SCHEMA IF EXISTS db_test01;

数据表操作

-- 建表
CREATE TABLE [ IF NOT EXISTS ] table_name (
 colName1 type1 comment,
 colName2 type2 comment,
 colName3 type3 comment,
 ……
 colNameN typeN comment
)
[ COMMENT table_comment ]
[ WITH ( property_name = expression [, ...] ) ]

CREATE TABLE default.orders (
 orderkey bigint,
 orderstatus varchar,
 totalprice double,
 orderdate date
)
COMMENT 'A table to keep track of orders.'
WITH (format = 'ORC')

-- 列举
SHOW TABLES

-- 查看
DESC table_name

-- 删表
DROP TABLE [ IF EXISTS ] table_name

DML语法
INSERT:会用到,将一条SQL语句的结果保存到表中

-- 语法
INSERT INTO table_name [ ( column [, ... ] ) ] query
-- 示例
INSERT INTO orders SELECT * FROM new_orders;
INSERT INTO cities VALUES (2, 'San Jose'), (3, 'Oakland');
INSERT INTO nation (nationkey, name, regionkey) VALUES (26, 'POLAND', 3);

注意:Presto不支持insert overwrite,如果想覆盖必须在Hive端先truncate table清空,然后再Presto中写入
DELETE

-- 语法
DELETE FROM table_name [ WHERE condition ]
-- 示例
DELETE FROM lineitem WHERE shipmode = 'AIR';
DELETE FROM lineitem WHERE orderkey IN (SELECT orderkey FROM orders WHERE priority = 'LOW');

注意:以上delete from…where语句在MySQL连接器支持,在Hive中不支持,但是在Hive端,支持delete from清空数据表操作!!!
DQL语法:主要在Presto中使用的语法

-- 基础语法
[ WITH with_query [, ...] ]
SELECT [ ALL | DISTINCT ] select_expr [, ...]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY [ ALL | DISTINCT ] grouping_element [, ...] ]
[ HAVING condition]
[ ORDER BY expression [ ASC | DESC ] [, ...] ]
[ { LIMIT [ count | ALL ] } ]

-- 子查询语法
SELECT a, b
FROM (
  SELECT a, MAX(b) AS b FROM t GROUP BY a
) AS x;

WITH x AS (SELECT a, MAX(b) AS b FROM t GROUP BY a)
SELECT a, b FROM x;

-- JOIN语法
[ INNER ] JOIN
LEFT [ OUTER ] JOIN
RIGHT [ OUTER ] JOIN
FULL [ OUTER ] JOIN
CROSS JOIN

-- 示例1:基础查询
SELECT 
     count(*), 
     mktsegment, 
     nationkey,
     CAST(sum(acctbal) AS bigint) AS totalbal
FROM customer
GROUP BY mktsegment, nationkey
HAVING sum(acctbal) > 5700000
ORDER BY totalbal DESC;

-- 示例2:子查询
SELECT 
   name
FROM nation
WHERE regionkey IN (SELECT regionkey FROM region)

-- 示例3:JOIN
SELECT 
    *
FROM table_1
JOIN table_2
ON table_1.key_A = table_2.key_A AND table_1.key_B = table_2.key_B

函数
数学函数:https://prestodb.io/docs/current/functions/math.html
聚合函数:https://prestodb.io/docs/current/functions/aggregate.html
字符函数:https://prestodb.io/docs/current/functions/string.html
日期函数:https://prestodb.io/docs/current/functions/datetime.html
窗口函数:https://prestodb.io/docs/current/functions/window.html

工作中使用
DDL:一般在数据源【Hive、MySQL】中执行建库建表
DML:Presto中通过insert将Select语句的结果进行保存
DQL:Presto中通过select语句查询处理数据

Presto基本语法与MySQL和Hive类似,但是有所不同
工作中:Hive负责建库、建表以及导入数据,Presto一般负责复杂业务的查询

4 Presto的使用优化

比较 Impala、Presto、Spark
Impala:性能最快、集成HDFS的数据接口、SQL语法支持非常差

用起来不方便,接口比较少
场景:使用Impala对Hive或者Hbase中的数据进行即席查询或者计算

Presto:性能第二快、集成多种数据源接口

支持大数据接口的语法不统一,单一SQL内存计算功能
场景:高性能多数据源集成数据查询、处理

Spark:性能最慢,全场景的数据处理平台【离线计算、实时计算、机器学习、图计算:Python、Java、Scala、SQL、R】

架构的设计导致实时计算性能不是特别完善 => Flink
场景:用一个工具解决整套数据处理的方案

优化方法:
优化一:分区裁剪
适当对数据表进行分区,当我们筛选数据时,可以通过where指定要查询的分区(分区裁剪)

Hive类似,Presto会根据元信息读取分区数据,合理的分区能减少Presto数据读取量,提升查询数据性能。

优化二:ORC列式存储 => Presto => ORC

Presto对ORC文件读取做了特定优化,因此在Hive中创建Presto使用的表时,建议采用ORC格式存储。相对于Parquet,Presto对ORC支持更好。
Parquet和ORC一样都支持列式存储,但是Presto对ORC支持更好,而Impala对Parquet支持更好。在数仓设计时,要根据后续可能的查询引擎合理设置数据存储格式。

优化三:数据压缩

数据压缩可以减少节点间数据传输对IO带宽压力,对于即席查询需要快速解压,建议采用Snappy压缩。

优化四:预先排序
对于已经排序的数据,在查询的数据过滤阶段,ORC格式支持跳过读取不必要的数据。
比如对于经常需要过滤的字段可以预先排序。

-- 写入数据时排序
INSERT INTO table nation_orc partition(p)
SELECT * FROM nation SORT BY n_name;
-- 如果需要过滤n_name字段,则性能将提升。
SELECT count(*) FROM nation_orc WHERE n_name=’AUSTRALIA’; 

5 Presto的内存分配

内存分类:
user memory:用户内存

跟用户数据相关的,比如读取用户输入数据会占据相应的内存,这种内存的占用量跟用户底层数据量大小是强相关的

system memory:系统内存

执行过程中衍生出的副产品,比如tablescan表扫描,write buffers写入缓冲区,跟查询输入的数据本身不强相关的内存。

内存池:内存池中来实现分配user memory和system memory
GENERAL_POOL:主要使用的内存

一般情况下,一个查询执行所需要的user/system内存都是从general pool中分配的,reserved pool在一般情况下是空闲不用的

RESERVED_POOL:备份内存

大部分时间里是不参与计算的,但是当集群中某个Worker节点的general pool消耗殆尽之后,coordinator会选择集群中内存占用最多的查询,把这个查询分配到reserved pool,这样这个大查询自己可以继续执行,而腾出来的内存也使得其它的查询可以继续执行,从而避免整个系统阻塞。

注意:reserved pool的设计问题

  • 空间大小:大小上限就是集群允许的最大的查询的大小(query.total-max-memory-per-node)
  • 设计缺点:普通模式下这块内存用不到的时候就是浪费的资源,对于较大的查询一般不建议使用Presto来实现
  • 禁用功能:experimental.reserved-pool-enabled设置为false
  • 内存耗尽:物理内存耗尽时,有一个OOM Killer的机制,对于超出内存限制的大查询SQL将会被系统Kill掉
  • 注意:如果在使用Presto进行较为复杂或较大数据分析时,如果Presto worker节点突然断开,很大一部分原因就是因为OOM内存溢出,系统主动杀死了最占用内存的进程。

相关参数
user memory用户内存参数

query.max-memory-per-node:单个query操作在单个worker上user memory能用的最大值
query.max-memory:单个query在整个集群中允许占用的最大user memory

user+system总内存参数

query.max-total-memory-per-node:单个query操作可在单个worker上使用的最大(user + system)内存
query.max-total-memory:单个query在整个集群中允许占用的最大(user + system) memory

协助阻止机制:在高内存压力下保持系统稳定

当general pool常规内存池已满时,操作会被置为blocked阻塞状态,直到通用池中的内存可用为止。
此机制可防止激进的查询填满JVM堆并引起可靠性问题。

其他参数

memory.heap-headroom-per-node:这个内存是JVM堆中预留给第三方库的内存分配,presto无法跟踪统计,默认值是-Xmx * 0.3
-Xmx3G
预留第三方库内存大小 = 3G * 0.3 = 0.9G

结构

GeneralPool = 服务器总内存 - ReservedPool - memory.heap-headroom-per-node - Linux系统内存
常规内存池内存大小 = 服务器物理总内存 - 服务器linux操作系统内存- 预留内存池大小 - 预留给第三方库内存

常见的报错解决

1、Query exceeded per-node total memory limit of xx
适当增加query.max-total-memory-per-node。
2、Query exceeded distributed user memory limit of xx
适当增加query.max-memory。
3、Could not communicate with the remote task. The node may have crashed or be under too much load
内存不够,导致节点crash,可以查看/var/log/message。

建议参数设置

1、query.max-memory-per-node和query.max-total-memory-per-node是query操作使用的主要内存配置,因此这两个配置可以适当加大。
2、memory.heap-headroom-per-node是三方库的内存,默认值是JVM-Xmx * 0.3,可以手动改小一些。
3、 各节点JVM内存推荐大小: 当前节点剩余内存*80% => free -h
4、 对于heap-headroom-pre-node第三方库的内存配置: 建议jvm内存的15%左右
5、 在配置的时候, 不要正正好, 建议多预留一点点, 以免出现问题

注意:

1、query.max-memory-per-node小于query.max-total-memory-per-node。
2、query.max-memory小于query.max-total-memory。
3、query.max-total-memory-per-node 与memory.heap-headroom-per-node 之和必须小于 jvm max memory,也就是jvm.config 中配置的-Xmx。
3G + -Xmx5G * 0.3 = 3G + 1.5G = 4.5G
-Xmx5G

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值