0、配景
上周四接到反馈,集群部门 spark 任务执行很慢,且常常堕落,参数改来改去怎么都无法优化其机能息争决频繁随机报错的问题。
看了下任务的汗青运行环境,平均时间 3h 阁下,并且极其不不变,偶然还会报错:
1、优化思路
任务的运行时间跟什么有关?
(1)数据源巨细差别
在有限的计较下,job的运行时长和数据量巨细正相关,在本例中,数据量巨细根基不变,可以解除是日志量级颠簸导致的问题:
(2)代码自己逻辑缺陷
好比代码里反复建设、初始化变量、情况、RDD资源等,随意耐久化数据等,大量利用 shuffle 算子等,好比reduceByKey、join等算子。
在这份100行的代码里,一共有 3 次 shuffle 操纵,任务被 spark driver 切分成了 4 个 stage 串行执行,代码位置如下:
咱们需要做的就是从算法和业务角度尽大概淘汰 shuffle 和 stage,晋升并行计较机能,这块是个大的话题,本次不展开详述。
(3)参数配置不公道
这块能力相对通用,咱们来看看之前的焦点参数配置:
num-executors=10 || 20 ,executor-cores=1 || 2, executor-memory= 10 || 20,driver-memory=20,软件开发,spark.default.parallelism=64
假设咱们的 spark 行列资源环境如下:
memory=1T,cores=400
参数怎么配置在这里就有些能力了,首先得大白 spark 资源的分派和利用道理:
在默认的非动态资源分派场景下, spark 是预申请资源,任务还没起跑就独有资源,一直到整个 job 所有 task 竣事,好比你跳板机起了一个 spark-shell 一直没退出,也没执行任务,那也会一直占有所有申请的资源。(假如配置了 num-executors,动态资源分派会失效)
留意上面这句话,spark 的资源利用分派方法和 mapreduce/hive 是有很大不同的,假如不领略这个问题就会在参数配置上激发其它问题。
好比 executor-cores 设几多符合?少了任务并行度不可,多了会把整个行列资源独有耗光,其他同学的任务都无法执行,好比上面谁人任务,在 num-executors=20 executor-cores=1 executor-memory= 10 的环境下,会独有20个cores,200G内存,一直一连3个小时。
那针对本case中的任务,团结咱们现有的资源,如何配置这 5 个焦点参数呢?
1) executor_cores*num_executors 不宜太小或太大!一般不高出总行列 cores 的 25%,好比行列总 cores 400,最大不要高出100,最小不发起低于 40,除非日志量很小。
2) executor_cores 不宜为1!不然 work 历程中线程数过少,一般 2~4 为宜。
3) executor_memory 一般 6~10g 为宜,最大不高出 20G,不然会导致 GC 价钱过高,或资源挥霍严重。
4) spark_parallelism 一般为 executor_cores*num_executors 的 1~4 倍,系统默认值 64,不配置的话会导致 task 许多的时候被分批串行执行,或大量 cores 空闲,资源挥霍严重。
5) driver-memory 早前有同学配置 20G,其实 driver 不做任何计较和存储,只是下发任务与yarn资源打点器和task交互,除非你是 spark-shell,不然一般 1-2g 就够了。
Spark Memory Manager:
6)spark.shuffle.memoryFraction(默认 0.2) ,也叫 ExecutionMemory。这片内存区域是为了办理 shuffles,joins, sorts and aggregations 进程中为了制止频繁IO需要的buffer。假如你的措施有大量这类操纵可以适当调高。
7)spark.storage.memoryFraction(默认0.6),也叫 StorageMemory。这片内存区域是为了办理 block cache(就是你显示挪用dd.cache, rdd.persist等要领), 尚有就是broadcasts,以及task results的存储。可以通过参数,软件开发,假如你大量挪用了耐久化操纵或广播变量,那可以适当调高它。
8)OtherMemory,给系统预留的,因为措施自己运行也是需要内存的, (默认为0.2)。Other memory在1.6也做了调解,担保至少有300m可用。你也可以手动配置 spark.testing.reservedMemory . 然后把实际可用内存减去这个reservedMemory获得 usableMemory。 ExecutionMemory 和 StorageMemory 会共享usableMemory * 0.75的内存。0.75可以通过 新参数 spark.memory.fraction 配置。今朝spark.memory.storageFraction 默认值是0.5,所以ExecutionMemory,StorageMemory默认环境是均分上面提到的可用内存的。
譬喻,假如需要加载大的字典文件,可以增大executor中 StorageMemory 的巨细,这样就可以制止全局字典换入换出,淘汰GC,在这种环境下,软件开发,我们相当于用内存资源来调换了执行效率。