Spark性能优化合理设置并行度

1 Hadoop文件和block的关系,split与block的关系,一个map对应一个split分片吗?

1.1 Hadoop文件和block的关系

    在介绍hadoop写文件的时候我们经常会说首先分割文件为多个块;那么是怎么分割的呢?这里其实不要有过的纠结,这里的块是block,是hdfs中切块的大小,属于物理划分,默认128M,在hadoop-default.xml配置中有体现,也可以修改。

1.2 什么是split,它与block的关系

    首先,split是mapreduce中的概念,而block是hdfs中切块的大小。

    totalSize:是整个Map-Reduce job所有输入的总大小。

    numSplits:来自job.getNumMapTasks(),即在job启动时用org.apache.hadoop.mapred.JobConf.setNumMapTasks(intn)设置的值,给M-R框架的Map数量的提示。

    goalSize:是输入总大小与提示Map task数量的比值,即期望每个Mapper处理多少的数据,仅仅是期望,具体处理的数据数由下面的computeSplitSize决定。

    minSplitSize:默认为1,可由子类复写函数protected void setMinSplitSize(long minSplitSize) 重新设置。一般情况下,都为1,特殊情况除外。

    minSize:取的1和mapred.min.split.size中较大的一个。

    blockSize:HDFS的块大小,默认为64M,一般大的HDFS都设置成128M。

    splitSize:就是最终每个Split的大小,那么Map的数量基本上就是totalSize/splitSize。

    接下来看看computeSplitSize的逻辑:首先在goalSize(期望每个Mapper处理的数据量)和HDFS的block size中取较小的,然后与mapred.min.split.size相比取较大的。

    一个片为一个splits,即一个map,只要搞清楚片的大小,就能计算出运行时的map数。而一个split的大小是由goalSize,minSize, blockSize这三个值决定的。computeSplitSize的逻辑是,先从goalSize和blockSize两个值中选出最小的那个(比如一般不设置map数,这时blockSize为当前文件的块size,而goalSize是文件大小除以用户设置的map数得到的,如果没设置的话,默认是1),在默认的大多数情况下,blockSize比较小。然后再取blockSize和minSize中最大的那个。而minSize如果不通过”mapred.min.split.size”设置的话(”mapred.min.split.size”默认为0),minSize为1,可理解为一个block块,这样得出的一个splits的size就是blockSize,即一个块一个map,有多少块就有多少map。

    split的大小是默认和hdfs的block块大小一致,但是可以通过配置文件自己设置: 其中有俩个配置文件(如下):

        --minsize   默认大小为1

            mapreduce.input.fileinputformat.split.minsize 

        --maxsize   默认大小为Long.MAXValue

            mapreduce.input.fileinputformat.split.maxsize

    这里我们可以总结下split大小与block的关系:

        (1)block块的大小小于split分片的最小值,那split的值就是split分片的大小

        (2)block块的大小介于split分片配置的最小值和最大值之间,block的大小就是split的大小。

        (3)block块的大小大于split分片的最大值,split的大小就是split配置的最大值。但会增加map执行的并发度,但是会造成在节点之间拉取数据

1.3 map和split的关系

    一个map对应一个split分片吗?经过上面的讨论,答案是显而易见的:map个数由任务切片spilt决定的,默认情况下一个split的大小就是block。

2 Spark的并行度指的是什么?

    spark作业中,各个stage的task的数量,也就代表了spark作业在各个阶段stage的并行度!

    当分配完所能分配的最大资源了,然后对应资源去调节程序的并行度,如果并行度没有与资源相匹配,那么导致你分配下去的资源都浪费掉了。同时并行运行,还可以让每个task要处理的数量变少(很简单的原理。合理设置并行度,可以充分利用集群资源,减少每个task处理数据量,而增加性能加快运行速度。)

    举例:假如, 现在已经在spark-submit 脚本里面,给我们的spark作业分配了足够多的资源,比如50个executor ,每个executor有10G内存,每个executor有3个cpu core 。 基本已经达到了集群或者yarn队列的资源上限。task没有设置,或者设置的很少,比如就设置了100个task 。 50个executor ,每个executor 有3个core ,也就是说Application任何一个stage运行的时候,都有总数150个cpu core ,可以并行运行。但是,你现在只有100个task ,平均分配一下,每个executor 分配到2个task,ok,那么同时在运行的task,只有100个task,每个executor 只会并行运行 2个task。每个executor 剩下的一个cpu core 就浪费掉了!你的资源,虽然分配充足了,但是问题是,并行度没有与资源相匹配,导致你分配下去的资源都浪费掉了。

    合理的并行度的设置,应该要设置的足够大,大到可以完全合理的利用你的集群资源;比如上面的例子,总共集群有150个cpu core ,可以并行运行150个task。那么你就应该将你的Application的并行度,至少设置成150个,才能完全有效的利用你的集群资源,让150个task 并行执行,而且task增加到150个以后,即可以同时并行运行;还可以让每个task要处理的数量变少,比如总共 150G 的数据要处理, 如果是100个task ,每个task 要计算1.5G的数据。现在增加到150个task,每个task只要处理1G数据。

3 何去提高并行度?

    Task数量,至少设置成与spark Application 总cpu core 数量相同(最理性情况,150个core,分配150task,一起运行,差不多同一时间运行完毕)官方推荐,task数量,设置成spark Application 总cpu core数量的2~3倍,比如150个cpu core ,基本设置 task数量为 300~ 500. 与理性情况不同的,有些task 会运行快一点,比如50s 就完了,有些task 可能会慢一点,要一分半才运行完,所以如果你的task数量,刚好设置的跟cpu core 数量相同,可能会导致资源的浪费,因为比如150task ,10个先运行完了,剩余140个还在运行,但是这个时候,就有10个cpu core空闲出来了,导致浪费。如果设置2~3倍,那么一个task运行完以后,另外一个task马上补上来,尽量让cpu core不要空闲。同时尽量提升spark运行效率和速度,提升性能。

3.1 在shuffle阶段设置增加partitions

    spark.defalut.parallelism   默认是没有值的,如果设置了值比如说10,是在shuffle的过程才会起作用

        例如:(val rdd2 =rdd1.reduceByKey(_+_) //rdd2的分区数就是10,rdd1的分区数不受这个参数的影响)

        newSparkConf().set(“spark.defalut.parallelism”,“500”)

3.2 增加HDFS上block数

    如果读取的数据在HDFS上,增加block数,默认情况下split与block是一对一的,而split又与RDD中的partition对应,所以增加了block数,也就提高了并行度。

3.3 重新设置partition的数量

    RDD.repartition(参数),给RDD重新设置partition的数量

    reduceByKey的算子指定partition的数量

        例如:  val rdd2 =rdd1.reduceByKey(_+_,10) 

        valrdd3 = rdd2.map.filter.reduceByKey(_+_)

    使用join算子的时候,增加父RDD中partition的数量

        例如:val rdd3 = rdd1.join(rdd2)  rdd3里面partiiton的数量是由父RDD中最多的partition数量来决定,因此使用join算子的时候,增加父RDD中partition的数量。

3.4 设置spark sql shuffle中的partitions数量

    spark sql中shuffle过程中partitions的数量需要通过参数设置:spark.sql.shuffle.partitions

4 Spark on Yarn: job提交重要参数说明

    当在YARN上运行Spark作业,每个Spark executor作为一个YARN容器运行。Spark可以使得多个Tasks在同一个容器里面运行。

4.1 spark-submit提交参数

参数名称

含义

--master MASTER_URL

yarn

--deploy-mode DEPLOY_MODE

Driver程序运行的地方:client、cluster

--class CLASS_NAME

应用程序主类名称,含包名

例如: org.apache.spark.examples.SparkPi

--name NAME

应用程序名称

--jars JARS

Driver和Executor依赖的第三方jar包

--properties-file FILE

应用程序属性的文件路径,默认是conf/spark-defaults.conf

--conf PROP=VALUE          

给spark配置其他属性

 以下设置Driver

--driver-cores NUM 

Driver程序使用的CPU核数(只用于cluster),默认为1  

--driver-memory MEM

Driver程序使用内存大小,推荐值2-6G,不宜太大

--driver-library-path

Driver程序的库路径

--driver-class-path

Driver程序的类路径

--driver-java-options

给Driver传入的java选项

 以下设置Executor

--num-executors NUM

启动的executor的数量,默认为2

--executor-cores NUM

每个executor分配的CPU核心数,默认为1,设置单个executor能并发执行task数,根据job设置,推荐值2-16 (这里不是指CPU数,集群不限制CPU使用)

--executor-memory MEM

每个executor内存大小,默认为1G,

根据job需求以及并发数设置,最大不要超过30G

--queue QUEUE_NAME

提交应用程序给哪个YARN的队列,默认是default队列

--archives ARCHIVES

逗号分隔的档案列表,将被放置到每个执行者的工作目录中

--files FILES

用逗号隔开的要放置在每个executor工作目录的文件列表

4.2配置spark各项指标参数

4.2.1设置内存用来作为cache的比例,0.1 为10% (默认为0.6),如果不用内存cache,设置为0

    --confspark.storage.memoryFraction=0.1  

4.2.2禁止使用内存cache

    --confspark.hadoop.fs.hdfs.impl.disable.cache=true 

4.2.3控制Spark中的分布式shuffle过程默认使用的task数量,默认Others: total number of cores on all executor nodes or 2, whicheveris larger,我们建议为每一个CPU核(core)分配2-3个任务

    --confspark.default.parallelism=400    

4.2.4调整split文件大小

    --confspark.hadoop.mapreduce.input.fileinputformat.split.minsize=134217728  

4.3计算公式:

4.3.1 containers的最大值就是spark 设置的 num-executors值 ;

4.3.2实际占用的总的vcores≈(executor-cores)*containers(实际executors)

4.3.3内存计算公式:((实际占用的总的containers)*(executor-memory+512M))+(driver-memory)。

5参考网站

https://blog.csdn.net/csdnliuxin123524/article/details/80169792

http://spark.apache.org/docs/1.3.0/running-on-yarn.html

https://www.cnblogs.com/liugh/p/6953010.html

 


你可能感兴趣的:(Spark)