大数据SQL调优专题——Spark执行原理

引入

深入MapReduce中有提到,MapReduce虽然通过“分而治之”的思想,解决了海量数据的计算处理问题,但性能还是不太理想,这体现在两个方面:

  1. 每个任务都有比较大的overhead,都需要预先把程序复制到各个 worker 节点,然后启动进程;
  2. 所有的中间数据都要读写多次硬盘。map 的输出结果要写到硬盘上,reduce抓取数据排序合并之后,也要先写到本地硬盘上再进行读取,所以快不起来。

除此之外,MapReduce还有以下的问题:

  1. 算子不够丰富,仅有Map和Reduce,复杂算子的实现极为烦琐;
  2. MapReduce在处理迭代计算、实时查询和交互式数据挖掘任务时效率较低,因为每次迭代都需要将数据写入磁盘,导致大量的I/O开销;
  3. 无法支持血缘或上下游依赖的概念,失败重试只能从头开始,变相地无法实现迭代计算。

针对以上的缺陷,不同的计算引擎采取了不同的优化策略。例如Tez简化了MapReduce过程,支持DAG(Directed Acyclic Graph,有向无环图)​,细化MapReduce环节并灵活组合。Impala则专注于单节点纯内存计算。而Spark依托DAG Lineage、纯内存计算、RDD(分布式弹性数据集)等特性,以及与Hadoop生态极佳的兼容性,支持例如图计算、机器学习、流(Micro-Batch)计算等多样化的功能或场景,在一系列大数据引擎中脱颖而出,成为当今最主流的计算引擎之一。

Spark最初由加州大学伯克利分校的AMPLab开发,后来成为Apache软件基金会的顶级项目。

Spark的核心概念

下面通过Spark的一些核心概念,去进一步了解它。

RDD(弹性分布式数据集)

定义

RDD(Resilient Distributed Dataset)是Spark的核心抽象,是一个不可变的、分布式的数据集合,可以并行操作。RDD可以通过在存储系统中的文件或已有的Scala、Java、Python集合以及通过其他RDD的转换操作来创建。

特性

  • 不可变性:RDD一旦创建,其数据就不能被修改。

  • 分区:RDD的数据被划分为多个分区,每个分区可以独立计算。

  • 依赖关系:RDD之间通过转换操作形成依赖关系,这些依赖关系构成了DAG(有向无环图)

DAG(有向无环图)

定义

DAG是Spark中用于表示RDD之间依赖关系的有向无环图。DAG调度器负责将DAG分解成多个阶段(stages),每个阶段是一系列并行的任务。

工作原理

  1. 操作解析:当代码被提交到Spark的解释器时,系统会生成一个操作图,称为Operator Graph,记录了所有的Transformation操作及其依赖关系。

  2. DAG调度器:当一个Action操作(如collect或save)被触发时,DAG调度器会将Operator Graph分解为多个Stage(阶段)。窄依赖(Narrow Dependency)的操作如map和filter不需要数据重新分区,属于同一阶段;宽依赖(Wide Dependency)的操作如reduceByKey需要数据Shuffle,不同阶段之间以宽依赖为界。

  3. 任务调度器:每个Stage会被拆分为多个基于数据分区的Task。Task调度器将这些Task分发到集群的Worker节点上执行。

  4. 执行与结果:每个Worker节点执行分配的Task,并将结果返回给Driver程序。DAG确保各个阶段按依赖顺序执行,并通过内存优化中间结果存储,最大限度减少I/O和通信开销。

作用

  • 任务依赖分析:DAG调度器通过分析RDD之间的依赖关系,决定任务的执行顺序。

  • 内存计算优化:通过减少Shuffle和磁盘读写,DAG提高了计算效率。

  • 全局优化:DAG确保每个Stage都包含最少的任务,避免重复计算。

Shuffle机制

定义

Shuffle是Spark中的一种数据重新分区操作,通常在宽依赖(Wide Dependency)的操作中发生,如reduceByKey、groupByKey等。

工作原理

  1. 分区:Shuffle操作会将数据重新分区,通常会根据键(key)进行分区。

  2. 数据传输:数据从一个节点传输到另一个节点,以确保相同键的数据位于同一个节点上。

  3. 排序和分组:在目标节点上,数据会被排序和分组,以便进行后续的聚合操作。

优化策略

  • 减少数据传输:通过数据本地性优化,尽量减少数据在节点之间的传输。

  • 压缩:在Shuffle过程中,可以启用数据压缩,减少网络传输的开销。

  • 缓存:在Shuffle之前,可以将数据缓存到内存中,减少重复计算。

数据缓存机制

定义

数据缓存机制是Spark中用于提高数据处理效率的一种机制,通过将数据缓存到内存中,减少重复计算的开销。

实现方式

  • cache()cache()方法是persist()的简化版,其底层实现直接调用persist(StorageLevel.MEMORY_AND_DISK),默认将数据存储在内存中,如果内存不足,则溢写到磁盘。

  • persist()persist()方法允许用户选择存储级别StorageLevel,如MEMORY_ONLYMEMORY_AND_DISKDISK_ONLY等。

作用

  • 加速重复计算:通过缓存数据,避免重复计算DAG中的父节点。

  • 灵活的存储策略persist()方法提供了更灵活的存储策略,适应内存、磁盘等不同环境。

适用场景

  • 数据需要被多次使用:适用于数据需要被多次使用,但不需要跨作业的容错能力的场景。

  • 计算代价大:适用于计算代价大,但内存能够容纳数据的场景。

错误容忍机制

RDD的DAG Lineage(血缘)

指创建RDD所依赖的转换操作序列。当某个RDD的分区数据丢失时,Spark可以通过Lineage信息重新计算该分区的数据。

RDD的 DAG Lineage 主要用于描述数据从源到目标的转换过程,包括数据的流动、处理、转换等各个步骤。DAG Lineage能够清晰地展示数据的来源、去向以及数据在不同阶段的变化,帮助用户了解数据的全生命周期。

Checkpoint(检查点)

通过将RDD的状态保存到可靠的存储系统(如HDFS、S3等),以支持容错和优化长计算链。当Spark应用程序出现故障时,可以从检查点恢复状态。

故障恢复

  • 节点故障:当Worker节点故障时,Spark会利用RDD的血统信息重新计算丢失的数据分区。如果设置了检查点,Spark会从检查点位置开始重新执行,减少计算开销。
  • 驱动节点故障:如果驱动节点故障,Spark会通过Apache Mesos等集群管理器重新启动驱动节点,并恢复执行状态。

内存管理机制

内存模型

执行内存(Execution Memory):主要用于存储任务执行过程中的临时数据,如Shuffle的中间结果等。这部分内存主要用于任务的执行期间,任务完成后会被释放。

存储内存(Storage Memory):用于缓存中间结果(RDD)和DataFrame/DataSet的持久化数据。这部分内存是为了加速重复计算而存在的,数据可以被多次复用。

内存分配

内存分配比例:内存分配比例可以通过配置项spark.executor.memory来设置总的内存大小,并通过spark.storage.memoryFraction来指定存储内存所占的比例,默认为0.6。这意味着默认情况下,Executor的60%的内存用于存储,剩余的40%用于执行。

内存回收

LRU缓存淘汰策略:Spark采用LRU(Least Recently Used)缓存淘汰策略来管理存储内存中的数据。当存储内存不足时,Spark会根据LRU算法淘汰最近最少使用的数据。

Spill to Disk:当执行内存不足时,Spark会将一部分数据溢写到磁盘,以释放内存空间。例如,在Shuffle操作期间,如果内存不足以存放所有中间结果,Spark会将部分数据写入磁盘。

动态内存管理

动态调整内存分配:在Spark 2.x版本之后,引入了更先进的内存管理机制,支持动态调整执行内存和存储内存之间的比例。这意味着在运行时,Spark可以根据实际内存使用情况动态调整内存分配,从而更好地利用资源。

内存配置

  • spark.executor.memory:设置Executor的总内存大小。
  • spark.storage.memoryFraction:设置存储内存所占的比例。
  • spark.shuffle.spill.compress:是否启用Shuffle数据的压缩。
  • spark.serializer:设置序列化库,默认为org.apache.spark.serializer.KryoSerializer。
  • spark.kryoserializer.buffer.max:设置Kryo序列化器的最大缓冲区大小。

Spark的执行原理

由于本专栏的重点是SQL,所以我们主要看Spark SQL的执行过程。相比于Hive的源码,Spark就贴心很多了,提供了org.apache.spark.sql.execution.QueryExecution类,这个类是Spark SQL查询执行的核心,它封装了从SQL解析到最终执行的整个过程,为开发者提供了丰富的接口来理解和调试查询执行的整个过程。

QueryExecution源码注释如下:</

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄雪超

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值