Spark性能调优

1、常规性能调优

1.1、常规性能调优方案一:最优资源配置

        Spark 性能调优的第一步,就是为任务分配更多的资源,在一定范围内,增加资源的分配与性能的提升是成正比的,实现了最优的资源配置后,在此基础上再考虑进行后面论述的性能调优策略。

        可以进行分配的资源如下表所示:

名称

说明

--driver-memory

配置driver内存(影响不大)

--executor-memory

配置每个executor的内存大小

--executor-cores

配置每个executor的CPU core的数量

--executor-instances

配置每个executor core的实例数

--num-executors

配置executor的数量

        调节原则:尽量将任务分配的资源调节到可以使用的资源的最大限度。Spark Yarn 模式,由于 Yarn 使用资源队列进行资源的分配和调度,在编写submit 脚本的时候,就根据 Spark 作业要提交到的资源队列,进行资源的分配,比如资源队列有 400G 内存,100 个 CPU core,那么指定 50 个 Executor,每个 Executor 分配8G 内存,2 个 CPU core。

        对各项资源进行了调节后,得到的性能提升会有如下表现:

名称

解析

增加 Executor个数

增加 Executor·个数在资源允许的情况下,增加 Executor 的个数 可以提高执行 task 的并行度。比如有 4 个 Executor,每个 Executor 有 2 个 CPU core,那 么可以并行执行 8 个 task,如果将 Executor 的 个数增加到 8 个(资源允许的情况下),那么 可以并行执行 16 个 task,此时的并行能力提 升了一倍。

增加每个 Executor 的 CPU core 个数

增加每个 Executor 的 CPU core 个数在资源允许的情况下,增加每个 Executor 的 Cpu core 个数,可以提高执行 task 的并行度。比如有 4 个 Executor,每个 Executor 有 2 个 CPU core,那么可以并行执行 8 个 task,如果 将每个 Executor 的 CPU core 个数增加到 4 个 (资源允许的情况下),那么可以并行执行 16 个 task,此时的并行能力提升了一倍。

增加每个 Executor 的内存量

在资源允许的情况下,增加每个 Executor 的 内存量以后,对性能的提升有三点: 1. 可以缓存更多的数据(即对 RDD 进行 cache),写入磁盘的数据相应减少,甚至 可以不写入磁盘,减少了可能的磁盘 IO;

 2. 可以为 shuffle 操作提供更多内存,即有更 多空间来存放 reduce 端拉取的数据,写入磁盘的数据相应减少,甚至可以不写入磁盘,减少了可能的磁盘 IO; 3. 可以为 task 的执行提供更多内存,在 task的执行过程中可能创建很多对象,内存较小时会引发频繁的 GC,增加内存后,可 以避免频繁的 GC,提升整体性能。

1.2、常规性能调优方案二:RDD优化

1.2.1、RDD复用

        在对 RDD 进行算子时,要避免相同的算子和计算逻辑之下对 RDD 进行重复的计算

Spark性能调优_第1张图片

         对上图中的 RDD 计算架构进行修改,得到如下图所示的优化结果:

Spark性能调优_第2张图片

 1.2.2、RDD持久化

        在 Spark 中,当多次对同一个 RDD 执行算子操作时,每一次都会对这个 RDD 以之前的父 RDD 重新计算一次,这种情况是必须要避免的,对同一个 RDD 的重复计算是对资源的极大浪费,因此,必须对多次使用的 RDD 进行持久化,通过持久化将公共 RDD 的数据缓存到内存/磁盘中,之后对于公共 RDD 的计算都会从内存/磁盘中直接获取 RDD 数据。对于 RDD 的持久化,有两点需要说明:

        (1)RDD 的持久化是可以进行序列化的,当内存无法将 RDD 的数据完整的进行存放的时候,可以考虑使用序列化的方式减小数据体积,将数据完整存储在内存中。

        (2)如果对于数据的可靠性要求很高,并且内存充足,可以使用副本机制,对 RDD 数据进行持久化。当持久化启用了复本机制时,对于持久化的每个数据单元都存储一个副本,放在其他节点上面,由此实现数据的容错,一旦一个副本数据丢失,不需要重新计算,还可以使用另外一个副本。

1.2.3、RDD尽可能早的filter操作

        获取到初始 RDD 后,应该考虑尽早地过滤掉不需要的数据,进而减少对内存的占用,从而提升 Spark 作业的运行效率。

1.3、常规性能调优方案三:并行度调节

        Spark 作业中的并行度指各个 stage 的 task 的数量。

        如果并行度设置不合理而导致并行度过低,会导致资源的极大浪费,例如, 20 个Executor,每个 Executor 分配 3 个 CPU core,而 Spark 作业有 40 个 task,这样每个 Executor 分配到的task 个数是 2 个,这就使得每个 Executor 有一个 CPU core 空闲,导致资源的浪费。

        理想的并行度设置,应该是让并行度与资源相匹配,简单来说就是在资源允许的前提下,并行度要设置的尽可能大,达到可以充分利用集群资源。合理的设置并行度,可以提升整个Spark 作业的性能和运行速度。

        Spark 官方推荐,task 数量应该设置为 Spark 作业总 CPU core 数量的 2~3 倍。之所以没有推荐 task 数量与 CPU core 总数相等,是因为 task 的执行时间不同,有的 task 执行速度快而有的 task 执行速度慢,如果 task 数量与 CPU core 总数相等,那么执行快的 task 执行完成后,会出现 CPU core 空闲的情况。如果 task 数量设置为 CPU core 总数的 2~3 倍,那么一个task 执行完毕后,CPU core 会立刻执行下一个 task,降低了资源的浪费,同时提升了 Spark作业运行的效率。

1.4、常规性能调优方案四:广播大变量

        默认情况下,task 中的算子中如果使用了外部的变量,每个 task 都会获取一份变量的复本,这就造成了内存的极大消耗。一方面,如果后续对 RDD 进行持久化,可能就无法将 RDD数据存入内存,只能写入磁盘,磁盘 IO 将会严重消耗性能;另一方面,task 在创建对象的时候,也许会发现堆内存无法存放新创建的对象,这就会导致频繁的 GC,GC 会导致工作线程停止,进而导致 Spark 暂停工作一段时间,严重影响 Spark 性能。

        假设当前任务配置了 20 个 Executor,指定 500 个 task,有一个 20M 的变量被所有 task共用,此时会在 500 个 task 中产生 500 个副本,耗费集群 10G 的内存,如果使用了广播变量, 那么每个 Executor 保存一个副本,一共消耗 400M 内存,内存消耗减少了 5 倍。广播变量在每个 Executor 保存一个副本,此 Executor 的所有 task 共用此广播变量,这让变量产生的副本数量大大减少。

        在初始阶段,广播变量只在 Driver 中有一份副本。task 在运行的时候,想要使用广播变量中的数据,此时首先会在自己本地的 Executor 对应的 BlockManager 中尝试获取变量,如果本地没有,BlockManager 就会从 Driver 或者其他节点的 BlockManager 上远程拉取变量的复本,并由本地的 BlockManager 进行管理;之后此 Executor 的所有 task 都会直接从本地的BlockManager 中获取变量。

你可能感兴趣的:(spark,big,data)