Presto 架构原理与优化介绍|青训营笔记
这是我参与「第四届青训营」笔记创作活动的的第5天。
一、课程概述
- 大数据与OLAP的演进之路,包括Presto的设计理念
- Presto的基础概念与原理
- Presto的特色和重要机制
- Presto常用优化
二、详细内容
1. OLAP概述
1.1 大数据
在信息化时代背景下由于信息交换(通信网络带宽的大幅增长),信息存储(计算机存储量的大幅增长)和信息处理(整理、转换、分析数据能力大幅增加)而产生的数据。
- 大数据不等价于大规模数据量
- Hadoop的出现:基于廉价机器的存算分离的大规模分布式处理系统
1.2 OLAP概述
- Online Analytical Processing
- 对业务数据进行多维分析,并提供复杂计算,趋势分析和复杂数据建模的能力
- 商务智能BI应用程序背后的技术
- 发展为基于数据库通过SQL对外提供分析能力
- OLAP vs MapReduce
- MapReduce代表抽象的物理执行模型,使用门槛较高
- 与MapReduce Job相比,OLAP引擎常通过SQL形式为数据分析数据开发人员提供统一的逻辑描述语言,实际的物理执行由具体的引擎进行优化和转换
- OLAP核心概念:维度+度量
- 常见的OLAP引擎
- 预计算引擎:Kylin,Druid
- 批式处理引擎:Hive,Spark
- 流式处理引擎:Flink
- 交互式处理引擎:Presto,Clickhouse,Doris
1.3 Presto设计理念
- 多租户任务的管理与调度
- 多数据源联邦查询
- 支持内存化计算
- pipeline式数据处理
2.Presto基础概念
Presto架构图
2.1 服务相关概念
- coordinator:负责调度(管理节点)
- 解析SQL语句
- 生成执行计划
- 分发执行任务给worker节点执行
- worker:工作节点
- 执行task处理数据
- 与其他worker交互传输数据
- 一个presto集群中存在一个coordinator节点和多个worker节点
- 每个节点上存在一个worker服务进程
- 数据处理
- task执行
- worker服务进程每隔一定时间向coordinator服务器发送心跳,接受调度
- 当客户提交查询时,coordinator会从当前存活的worker列表中选出适合的worker节点执行task
- worker在执行每个task时会进一步对当前task读入的每个split进行一系列操作和处理
2.2 数据源相关概念
- connector:支持多数据源的方式,一个connector代表一个数据源 (适配多数据源的统一接口)
- catalog:针对不同数据源connector和catalog一一对应,包含了schema和data source的映射关系 (源信息与实际数据的映射)
2.3 Query相关概念
- query:基于SQL parser后获得的执行计划
- stage:根据是否需要shuffle将query拆分成的不同subplan,每个subplan则是一个stage
- fragment:基本等价stage,不同阶段的称呼
- task:单个worker节点上最小的资源管理单元
- 一个节点上一个stage只有一个task
- 一个query可以有多个task
- pipeline:stage按照localExchange切分为若干operator的集合,每个operator集合定义一个pipeline
- driver:pipeline的可执行实体 (pipeline和driver类似程序和进程,是最小执行单元)通过火山迭代模型执行每一个operator
- split:输入数据描述(数据实体是page)
- 数量上和driver一一对应
- 不仅代表实际数据源split也代表不同stage间传输的数据
- operator:最小的物理算子
2.4 数据传输相关概念
- exchange:表示不同stage间的数据传输,大多数意义下等价于shuffle
- localExchange:stage内的rehash操作
- 常用于提高并行处理数据的能力
- task在presto中是最小的容器,而不是最小的执行单元
- 默认是16
- 如何衡量某个任务Stage的真实并行度:在不同pipeline下split(driver)的数目之和
2.5 核心组件架构介绍
- 服务发现 discovery service:将coordinator和worker结合在一起的服务
- (worker配置文件配置DS地址)
- worker节点启动后向discovery server服务注册
- coordinator从该server获得worker节点
- Presto的通信方式
- client与server:Http
- coordinator与worker:http/Thrift
- worker与worker间通信:http/Thrift
- thrift具有更好的数据编码能力,Http1.1不支持头部信息压缩,Thrift有更好的数据压缩率
- worker节点状态
- ACTIVE:活跃
- INACTIVE:不活跃
- SHUTDOWN:节点准备结束工作,进入shutdown状态,coordinator不再给节点分配工作,节点完成工作后结束
3. Presto的重要机制
3.1 Presto用户多租户隔离
Presto通过resource group对不同的用户创建不同group从而实现不同租户、不同场景的资源管理
3.2 Presto Resource Group优缺点
- 优点
- 支持通配符形式:简单配置文件实现
- 对不同租户不同提交场景下用户进行限制
- 缺点
- 存在滞后性
- 只会对group中正在运行的SQL资源进行判断
3.3Presto物理计划生成
- Antlr4解析生成AST
- 转换为Logical Plan
- 按照是否存在shuffle(exchange)切分为不同stage(fragment)
3.4Presto多租户任务调度
- stage调度
- AllAtOnceExecutionpolicy 同时调度
- 延迟低 存在任务空跑
- 典型应用为join查询
- build端右表构建join的hashtable
- probe端:左表数据进行探查,等待build完成
- build端构建hashtable时probe在空跑
- phased Execution policy
- 不代表每个stage都分开调度
- 可以分开处理,无需等待stage完成
- 内存友好无需落盘
- 有一定延迟、节省部分资源
- AllAtOnceExecutionpolicy 同时调度
- task调度
- 数量确定
- source:根据数据meta决定分配多少节点
- fixed:hash partition count确定如集群节点数量
- sink:汇聚结果一台机器
- scaled:无分区限制,可扩展,如write数据
- coordinator_only:只需要coordinator参与
- 选择什么节点
- HARD_AFFINITY:计算、存储local模式,保障计算与存储在同一节点减少数据传输
- SOFT_AFFINITY:基于某些特定算法,如一致性HASH函数;常用于缓存场景,保证相似的task调度到同一个worker
- NO_PREFERENCE:随机选取,常用于普通的纯计算Task
- 数量确定
- split调度
QueryA大SQL先提交,QueryB小SQL后提交,是否插队?
- FIFO:顺序执行,绝对公平
- 优先级调度:快速响应
- 按照固定时间片轮巡Split处理数据,处理1s再重新选择一个split执行
- split之间存在优先级
- multiLevelSplitQueue:五个优先级level理论上时间占比为16:8:4:2:1
- 优势
- 优先保证小query快速执行
- 保障大query存在固定比例时间片,不会被完全饿死 (优先级很低也能有时间)
3.5 内存计算
3.5.1 pipeline化的数据处理
- pipeline按照localExchange拆分
- 更好的实现算子间并行
- 语义上保证算子执行并行
3.5.2 back pressure mechanism
- 控制split生成流程
- 控制operator执行
- targetConcurrency auto-scale-out
- 定时检查如果outputbuffers使用率低于0.5(下游消费速度更快,需要提高生产数据),并发度+1
- sink.max-buffer-size写入buffer大小控制
- exchange.max-buffer-size读取buffer大小控制
- 达到最大值时operator进入阻塞状态
3.6 多数据源联邦查询
- 将各个数据源进行统一抽象,最后由presto server进行统一的物理执行
- 局限性
- 源数据管理与映射(每个connector管理一套源数据服务)
- 谓词下推(不同SQL处理不同)
- 数据源分片
4. Presto性能优化
4.1 常用的性能分析工具
- Grafana:埋点、系统指标如CPU、内存网络等可视化界面,时序化的数据展示
- 线上问题排查工具 Arthas:不重启服务可以监控
- watch/trace
- 需要自己猜出问题大体在哪一段
- Flame Figure火焰图
- 分析热点代码占用大量CPU从而导致服务性能下降情况
- java指令
- jstack查看java线程栈信息,排查死锁、异常线程
- JMX(Java Management Extensions)为应用程序植入管理功能框架,做监控指标的统计收集
- JMAP & GC日志等内存分析工具
- Presto UI
三、实践分析例
- data: tpcds 1T
- SQL:count(*) 3-4s
- 火焰图:可以看出某个方法占用大量CPU cycle
- 改进:逐元素copy大量hashmap的rehash操作 -> 对底层数据直接clone
- 优化:3-4s -> 1s
- SQL执行缓慢,某几个节点CPU负载特别高
- 问题:正则表达式完全由用户输入,而与正则表达式匹配的数据不可控,结果就是单条记录匹配需要天级别;正则表达式不可中断,阻塞了split的优先级调度
- 解决思路
- 能否实现可中断的正则表达式
- 其他类似问题处理方法
- 字节内部优化实践 - Multi Coordinator
- 问题:coordinator单节点实现性能差
- 优化:不可用时间减少,coordinator多活
- History Server
- presto UI存储在内存中无法长时间保存
- 持久化的数据存储
- support remote UDF
- 统一UDF抽象 适配多引擎
- 多租户内核与网络隔离
- raptorX多级缓存
- 在中间多级进行缓存,实现性能提升
- metastore cache by version
- list file cache
- fragment cache
- alluxio cache
四、课程总结
- 难点
- Presto的概念、原理
- Presto的优化
- 个人总结:本堂课学习了Presto相关的概念和原理,以及后期的优化。我个人对于Presto没有基础,需要在课后结合实践例、源代码进行进一步的深入学习。