前言
大部分做Spark开发的同学或多或少都做过很多的优化,事实上优化的策略是很多的,还有很多的默认策略做了其实是无感知,当时当某些场景数据规模比较庞大的时候就需要用户自己去控制优化策略了,我们希望对优化策略有个整体认识,然后我们做优化的时候才能够从多方面去切入。
优化策略的分类
针对各个场景优化做一个分类比较,然后对比较常用的参数进行举例说明
类型 | 优化位置 | 场景说明 | 优点 | 局限性 | 场景举例 |
Core | Spark-Core | Spark底层的执行策略,调度分配策略,shuffle等策略 | 影响覆盖面广,可编程性强,自然也比较灵活 | 需要比较底层的API控制,上手比较难 | Shuffle算法策略选择,task调度分配,超时控制等 |
RBO | 逻辑计划 | 主要是SQL的逻辑计划进行优化,基于经验规则的优化 | 优化策略比较明确,易于扩展规则策略,覆盖大部分的场景,本身成熟度高 | 作用度有所局限,不会根据数据特征进行优化,策略比较固化 | 常量折叠、谓词下推、操作合并、列裁剪、列裁剪下推,算子简化,条件简化等 |
CBO | 主要是针对物理计划进行优化 | 基于统计信息对执行计划进行调整 | 本身会考虑计算成本、可以根据数据分布进行优化、对数据敏感,自动性较强 | CBO本身基于统计信息进行优化,对数据采集影响大,数据不准确带来优化策略效果不好、收集统计信息本身带来计算成本 | Join顺序调整、Build侧选择、优化 Join 类型、优化多表 Join 顺序 |
AQE | 任务执行过程调整执行计划 | 执行过程中动态拉取执行数据调整执行计划 | 自动化强度高,自适应性强 | 比较新的策略,考虑的维度不是很高,目前覆盖场景不是很广 | 动态折叠shuffle过程中的partition、动态选择join策略、动态优化存在数据斜的join |
其他方面的优化和优化思路
shuffle的优化
shuffle实际上是需要经过重新进行文件的读写达到重新划分分区的目的,这期间带来比较大的IO操作,还一方面的原因是一般的大平台的nodemanager节点同时也会是DataNode的节点,两个操作都需要比较大量的RPC操作和IO的操作,在同时读写操作比较大的时候,会导致shuffle的失败,比较常见的思路就是减少同时操作的压力,剥离计算和存储节点,还有种做法是shuffle通过外部的服务,本质上都是解决这个shuffle带来的IO问题
计算的复用
计算的复用是通过执行策略进行操作的,Spark比较大的操作其实就是shuffle本身,spark对表的bucket存储可以把表的分桶信息进行物化,使用表的时候使用相同的bucket shuffle操作的时候可以复用这一次shuffle操作,不再需要进行shuffle的动作了,这块可以加速join 、group by、 over()这些操作是生产实践比较多的操作
使用列式存储
parquet和orc这类的存储格式实现了按列进行读写,大部分的情况下,我们其实不会需要把全部字段给查出来,按列式存储可以减少每次读取的数据量,另一方面列式存储在减少读取方面还做了一些文件下推操作的优化,可以按照文件读取的范围进行筛选。
合理使用数据类型
这个其实是比较常见的问题,但是实际应用时候问题比较多,很多场景数字类型使用了字符串保存,shuffle操作在数据量比较大的时候其实是需要进行排序,排序伴随的动作就是比较两个数据的大小,数子类型和字符串类型的大小比较复杂度其实是很不一样的,还一个就是数字类型比较大小时候结果其实和字符串结果并不一样,但是这个很多时候被忽略,另一方面数字类型可以明确划定范围,这个在列式存储优化时候也是作用很大。一方面为了结果准确需要精准给定数据类型,还以方面可以加速。
减少落地操作
在hive时代大部分是用一个临时表进行中间结果的存储,本身问题不大。但是到了spark时代,尤其是内存计算的时候频繁的落地显得会比较耗时,可以通过使用中间的临时视图进行中转结果,当然这种场景限于不是计算量很大的中间结果。
create temporary view view_xxx as select xxx from
merge on read
少量更新引发大量的IO,这个问题其实是当前平台的一个很大问题,这个当前delta lake的解决方案有了一些支持,但是传统sql通过bucket和view方案的操作可以带来很大的优化,具体解决的场景就是,我们需要合并一个历史数据和新增的数据时候,历史数据是一份大的base表数据,增量是比较少的数据量更新那么提前把历史数据bucket化,新增的数据做一次小bucket进行join,这种join其实可以维护成视图,我们在真正进行操作的时候调用这个视图,这样可以在shuffle和read的时候同时得到优化
总结
spark的优化可以从spark运行优化、sql执行策略、数据存储策略等方面同时进行优化,关键点不同策略其实着力点是不一样的,需要了解这个策略是在哪一个层次进行的优化才行!