Presto 在滴滴的探索和实践

Presto 简介

简介

Presto是Facebook 开源的 MPP (Massive Parallel Processing) SQL 引擎,其理念来源于一个叫 Volcano 的并行数据库,该数据库提出了一个并行执行 SQL 的模型,它被设计为用来专门进行高速、实时的数据分析。Presto是一个SQL计算引擎,分离计算层和存储层,其不存储数据,通过Connector SPI实现对各种数据源(Storage)的访问。

架构

Presto沿用了通用的Master-Slave架构,一个Coordinator,多个Worker。Coordinator负责解析SQL语句,生成执行计划,分发执行任务给Worker节点执行;Worker节点负责实际执行查询任务。Presto提供了一套Connector接口,用于读取元信息和原始数据,Presto 内置有多种数据源,如 Hive、MySQL、Kudu、Kafka 等。同时,Presto 的扩展机制允许自定义 Connector,从而实现对定制数据源的查询。假如配置了Hive Connector,需要配置一个Hive MetaStore服务为Presto提供Hive元信息,Worker节点通过Hive Connector与HDFS交互,读取原始数据。

实现低延时原理

Presto是一个交互式查询引擎,我们最关心的是Presto实现低延时查询的原理,以下几点是其性能脱颖而出的主要原因。

  • 完全基于内存的并行计算
  • 流水线
  • 本地化计算
  • 动态编译执行计划
  • 小心使用内存和数据结构
  • GC控制
  • 无容错

Presto 在滴滴的应用

业务场景

  • Hive SQL查询加速
  • 数据平台Ad-Hoc查询
  • 报表(BI报表、自定义报表)
  • 活动营销
  • 数据质量检测
  • 资产管理
  • 固定数据产品

Read More

Jetty导致Presto堆外内存泄露的排查过程

背景

一个Presto集群报警,显示Coordinator内存不足。看了下,发现RES内存(86.7G) > XMX(72G) + 堆外内存(10G),然后看了下Presto UI里Resource Utilization的Non-Heap Memory Used,只用了200M。问题奇怪,pmap查看进程的内存映像信息,如下:

1
2
3
4
5
6
7
8
9
10
11
12
[presto@hostname ~/presto-current]$ pmap -x 107870 | sort -rn -k3 | head -n 10
total kB 106752092 86763996 86684760
00007fd673000000 75644928 61078708 61078708 rw--- [ anon ]
00007fd5c8000000 2654208 2537116 2537116 rw--- [ anon ]
000000000120a000 1244772 1244644 1244644 rw--- [ anon ]
00007fd5803cf000 520388 497972 497972 rw--- [ anon ]
00007fd08c836000 149720 149720 149720 rw--- [ anon ]
00007fd0e2fe2000 147620 147620 147620 rw--- [ anon ]
00007fd0d9b35000 146920 146920 146920 rw--- [ anon ]
00007fe964000000 116672 114164 114164 rwx-- [ anon ]
00007fd0612b1000 111932 111932 111932 rw--- [ anon ]

第一列表示虚拟空间地址,第二列表示该项在虚拟空间中占用的大小,第三列表示RSS,第四列表示DIRTY,第五列表示该项名称(anon是佚名的)。

jmap -heap 发现堆内内存占用正常,然后我jmap dump了一份内存,dump后发现只有700M+,应该与堆内存无关了,既然这样查找直接从堆外内存入手了。

Read More

记一次Presto Worker OOM的查找过程

背景

最近Presto集群又上线了几个新业务,伴之而来的是OOM很频繁,且发生时间多在早晨8点左右,线上稳定性是高优需要解决的,所以查找了下导致Presto集群OOM的原因,发现了一些问题,这里抛砖引玉下,可能其他使用Presto的用户也会遇到类似的问题。

排查过程

我给一些业务划分了不同的label,这里说明下我们把Presto引擎改进了下,可以动态将机器划分不同的label,这样SQL查询时候指定不同的label,SQL调度时只根据指定的label查找机器即可。之后发现一个业务方的SQL会导致集群OOM。具体表现为,多次Full GC,之后OOM,看GC日志第一感觉应该是有内存泄露。

我通过审计日志(之前通过event-listener实现了个日志审计模块)拿到OOM时2K左右条SQL,发现SQL都是简单的SQL,类似这种:

1
2
SELECT * FROM table WHERE year='2020' AND month='06' AND day='01' LIMIT 10;

根据SQL,我猜测可能以下2种原因导致了OOM:

  • 查询的表存在Hive视图(我让Presto支持了Hive视图)
  • 异常SQL触发了内存泄露

Read More

PrestoDB和PrestoSQL比较及选择

Presto 社区分家后搞了2个项目,分别为 PrestoDB 和 PrestoSQL,同时他们都成立了自己的基金会。而去年国庆时候,abei写了篇文章比对了2个分支的进展,链接见:PrestoDB VS PrestoSQL发展比较。 而现在已经分家17个月了,那我们简单梳理下这2个分支的主要核心功能:

PrestoDB

  • Connector:ElasticSearch 及 Druid
  • Master 和Worker 通信协议支持二进制
  • Orc 及 Parquet读写性能优化
  • Hive写数据支持指定压缩格式
  • task通信协议可以指定 thrift
  • spi pushdown
  • MapReduce-style shuffle,支持部分 etl 任务及大查询
  • fix bug 及 improve performace

PrestoSQL

  • Connector:ElasticSearch和MemSQL
  • spi pushdown
  • S3优化读取
  • join 延时物化
  • 大量的 fix bug 及 improve performance

Read More

Presto调度task选择Worker方法

Presto调度task方式

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class SystemPartitioningHandle
implements ConnectorPartitioningHandle
{
private enum SystemPartitioning
{
SINGLE,
FIXED,
SOURCE,
SCALED,
COORDINATOR_ONLY,
ARBITRARY
}
}

常见的场景主要包含SINGLE、FIXED及SOURCE类型,其中SINGLE表示最后数据的汇总输出,FIXED表示中间数据的计算,如JOIN等,SOURCE类型表示与源数据打交道的类型。

以下SQL为例:

1
2
select * from (select * from 1test join 2test1 on 1test.id = 2test1.123id);

Read More

Presto集群内存不足时保护机制

为了防止集群里节点OOM,Presto有个循环线程来获取当前集群节点和集群整体内存占用情况。通过这篇文章:Presto内存管理相关参数设置 我们知道Presto里分为RESERVED_POOL和GENERAL_POOL。

判断节点是否阻塞(内存不足)

如果使用RESERVED_POOL(意思是说最大SQL使用这个POOL),那判断集群内存超出内存的方法就是:

1、RESERVED_POOL内存被SQL占用了

2、GENERAL_POOL里有被阻塞的Node

因为RESERVED_POOL会导致内存浪费,我们集群配置参数没有使用这个POOL,只使用了GENERAL_POOL,所以只需要查看下GENERAL_POOL是怎么判断节点是否Block住的。

1
2
3
4
if (poolInfo.getFreeBytes() + poolInfo.getReservedRevocableBytes() <= 0) {
blockedNodes++;
}

getReservedRevocableBytes 这个是用于获取spill到磁盘的内存,目前我们集群是不允许内存Spill到磁盘的,因为Presto面向的是ad-hoc场景,要求是快,如果说需要spill到磁盘,那spark是一个更好的选择,且早期版本Presto spill到磁盘之前测试过稳定性比较差,场景也比较少。

所以就判断GENERAL_POOL里是否还有剩余内存,如果小于等于0,那就表示该节点是个Block状态。

Read More

Presto内存管理相关参数设置

背景

之前介绍过Presto内存管理和分配策略,但是那个是0.192版本,详细见:Presto内存管理原理和调优 ,0.201之后内存管理作了新的修改,所以重新简单分析下,然后给出一个配置模板,希望对使用Presto的同学有帮助。

两种内存

Presto里面内存只有2种内存,一种是user memory,另一种是system memory。system memory用于input/output/exchange buffers等,user memory 用于hash join、agg这些。

内存池

0.201之前有3种内存POOL,分别是GENERAL_POOL、RESERVED_POOL及SYSTEM_POOL。但是0.201之后,默认SYSTEM_POOL是不开启的,以下参数控制,默认值为false

1
2
deprecated.legacy-system-pool-enabled

那SYSTEM_POOL不使用了,这块内存怎么控制呢,去代码里确认了下:

Read More