以前在Hive on Spark
跑TPCx-BB
测试时,100g的数据量要跑十几个小时,一看CPU和内存的监控,发现 POWER_TEST
阶段(依次执行30个查询)CPU只用了百分之十几,也就是没有把整个集群的性能利用起来,致使跑得很慢。所以,如何调整参数,使整个集群发挥最大性能显得尤其重要。web
Spark做业运行原理
详细原理见上图。咱们使用spark-submit提交一个Spark做业以后,这个做业就会启动一个对应的Driver进程。根据你使用的部署模式(deploy-mode)不一样,Driver进程可能在本地启动,也可能在集群中某个工做节点上启动。Driver进程自己会根据咱们设置的参数,占有必定数量的内存和CPU core。而Driver进程要作的第一件事情,就是向集群管理器(能够是Spark Standalone集群,也能够是其余的资源管理集群,美团•大众点评使用的是YARN做为资源管理集群)申请运行Spark做业须要使用的资源,这里的资源指的就是Executor进程。YARN集群管理器会根据咱们为Spark做业设置的资源参数,在各个工做节点上,启动必定数量的Executor进程,每一个Executor进程都占有必定数量的内存和CPU core。
缓存
Spark是根据shuffle类算子来进行stage的划分。若是咱们的代码中执行了某个shuffle类算子(好比reduceByKey、join等),那么就会在该算子处,划分出一个stage界限来。能够大体理解为,shuffle算子执行以前的代码会被划分为一个stage,shuffle算子执行以及以后的代码会被划分为下一个stage。所以一个stage刚开始执行的时候,它的每一个task可能都会从上一个stage的task所在的节点,去经过网络传输拉取须要本身处理的全部key,而后对拉取到的全部相同的key使用咱们本身编写的算子函数执行聚合操做(好比reduceByKey()算子接收的函数)。这个过程就是shuffle。微信
task的执行速度是跟每一个Executor进程的CPU core数量有直接关系的。一个CPU core同一时间只能执行一个线程。而每一个Executor进程上分配到的多个task,都是以每一个task一条线程的方式,多线程并发运行的。若是CPU core数量比较充足,并且分配到的task数量比较合理,那么一般来讲,能够比较快速和高效地执行完这些task线程。网络
以上就是Spark做业的基本运行原理的说明,你们能够结合上图来理解。理解做业基本原理,是咱们进行资源参数调优的基本前提。多线程
了解完了Spark做业运行的基本原理以后,对资源相关的参数就容易理解了。所谓的Spark资源参数调优,其实主要就是对Spark运行过程当中各个使用资源的地方,经过调节各类参数,来优化资源使用的效率,从而提高Spark做业的执行性能。如下参数就是Spark中主要的资源参数,每一个参数都对应着做业运行原理中的某个部分。并发
num-executors/spark.executor.instancesapp
参数说明:该参数用于设置Spark做业总共要用多少个Executor进程来执行。Driver在向YARN集群管理器申请资源时,YARN集群管理器会尽量按照你的设置来在集群的各个工做节点上,启动相应数量的Executor进程。这个参数很是之重要,若是不设置的话,默认只会给你启动少许的Executor进程,此时你的Spark做业的运行速度是很是慢的。函数
参数调优建议:每一个Spark做业的运行通常设置50~100个左右的Executor进程比较合适,设置太少或太多的Executor进程都很差。设置的太少,没法充分利用集群资源;设置的太多的话,大部分队列可能没法给予充分的资源。性能
executor-memory/spark.executor.memory测试
参数说明:该参数用于设置每一个Executor进程的内存。Executor内存的大小,不少时候直接决定了Spark做业的性能,并且跟常见的JVM OOM异常,也有直接的关联。
参数调优建议:每一个Executor进程的内存设置4G8G较为合适。可是这只是一个参考值,具体的设置仍是得根据不一样部门的资源队列来定。能够看看本身团队的资源队列的最大内存限制是多少,num-executors乘以executor-memory,是不能超过队列的最大内存量的。此外,若是你是跟团队里其余人共享这个资源队列,那么申请的内存量最好不要超过资源队列最大总内存的1/31/2,避免你本身的Spark做业占用了队列全部的资源,致使别的同窗的做业没法运行。
executor-cores/spark.executor.cores
参数说明:该参数用于设置每一个Executor进程的CPU core数量。这个参数决定了每一个Executor进程并行执行task线程的能力。由于每一个CPU core同一时间只能执行一个task线程,所以每一个Executor进程的CPU core数量越多,越可以快速地执行完分配给本身的全部task线程。
参数调优建议:Executor的CPU core数量设置为2~4个较为合适。一样得根据不一样部门的资源队列来定,能够看看本身的资源队列的最大CPU core限制是多少,再依据设置的Executor数量,来决定每一个Executor进程能够分配到几个CPU core。一样建议,若是是跟他人共享这个队列,那么num-executors * executor-cores不要超过队列总CPU core的1/3~1/2左右比较合适,也是避免影响其余同窗的做业运行。
driver-memory
参数说明:该参数用于设置Driver进程的内存。
参数调优建议:Driver的内存一般来讲不设置,或者设置1G左右应该就够了。惟一须要注意的一点是,若是须要使用collect算子将RDD的数据所有拉取到Driver上进行处理,那么必须确保Driver的内存足够大,不然会出现OOM内存溢出的问题。
spark.default.parallelism
参数说明:该参数用于设置每一个stage的默认task数量。这个参数极为重要,若是不设置可能会直接影响你的Spark做业性能。
参数调优建议:Spark做业的默认task数量为500~1000个较为合适。不少同窗常犯的一个错误就是不去设置这个参数,那么此时就会致使Spark本身根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task。一般来讲,Spark默认设置的数量是偏少的(好比就几十个task),若是task数量偏少的话,就会致使你前面设置好的Executor的参数都前功尽弃。试想一下,不管你的Executor进程有多少个,内存和CPU有多大,可是task只有1个或者10个,那么90%的Executor进程可能根本就没有task执行,也就是白白浪费了资源!所以Spark官网建议的设置原则是,设置该参数为num-executors * executor-cores的2~3倍较为合适,好比Executor的总CPU core数量为300个,那么设置1000个task是能够的,此时能够充分地利用Spark集群的资源。
spark.storage.memoryFraction
参数说明:该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。也就是说,默认Executor 60%的内存,能够用来保存持久化的RDD数据。根据你选择的不一样的持久化策略,若是内存不够时,可能数据就不会持久化,或者数据会写入磁盘。
参数调优建议:若是Spark做业中,有较多的RDD持久化操做,该参数的值能够适当提升一些,保证持久化的数据可以容纳在内存中。避免内存不够缓存全部的数据,致使数据只能写入磁盘中,下降了性能。可是若是Spark做业中的shuffle类操做比较多,而持久化操做比较少,那么这个参数的值适当下降一些比较合适。此外,若是发现做业因为频繁的gc致使运行缓慢(经过spark web ui能够观察到做业的gc耗时),意味着task执行用户代码的内存不够用,那么一样建议调低这个参数的值。
spark.shuffle.memoryFraction
参数说明:该参数用于设置shuffle过程当中一个task拉取到上个stage的task的输出后,进行聚合操做时可以使用的Executor内存的比例,默认是0.2。也就是说,Executor默认只有20%的内存用来进行该操做。shuffle操做在进行聚合时,若是发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地下降性能。
参数调优建议:若是Spark做业中的RDD持久化操做较少,shuffle操做较多时,建议下降持久化操做的内存占比,提升shuffle操做的内存占比比例,避免shuffle过程当中数据过多时内存不够用,必须溢写到磁盘上,下降了性能。此外,若是发现做业因为频繁的gc致使运行缓慢,意味着task执行用户代码的内存不够用,那么一样建议调低这个参数的值。
调优过程
数据量:10g
能够看出:
随着每一个executor占用的CPU core数增长,q04查询的时间显著降低,q03也降低,但幅度没那么大。
本次调优只设置了spark.executor.memory
和spark.executor.cores
两个参数,没有涉及到spark.executor.instances
参数,而默认的spark.executor.instances
为2,也就是每一个做业只用到2个executor,所以还没将性能发挥到最佳。
接下来采用100g的数据量,而且增长spark.executor.instances
参数的设置。
数据量:100g
能够看出:
调优先后查询时间有了很大的飞跃;
增长
spark.executor.instances
设置项指定每一个做业占用的executor个数后性能又有很大提高(经过监控咱们发现此时CPU利用率平均有好几十,甚至能够高到百分之九十几);至此,咱们终于将整个集群性能充分发挥出来,达到目的。
最后一列配置项是根据美团技术团队博客的建议设置的,能够看出性能相比咱们以前本身的设置仍是有必定提高的,至少该博客里建议的设置是比较通用的,所以以后咱们都采起最后一列的设置来跑TPCx-BB
测试。
最后来张大图展现调优前和调优后跑100g数据的对比:
能够看出:
绝大多数查询调优先后查询时间有了极大的飞跃;
可是像q01/q04/q14...这几个查询,可能由于查询涉及到的表比较小,调优前时间就很短,所以调优后也看不出不少差异,若是想看到大的差异,可能须要提升数据量,好比1T,3T;
q10和q18调优先后时间都较长,并且调优后性能没有提高,须要再深刻探索下是什么缘由。
最后,用调优后的集群,分别跑10g、30g、100g的数据,结果以下:
10g、30g、100g.jpg.png
能够看出:
随着数据量增大,不少查询时间并无明显增长,多是由于集群性能太强,并且数据量还不够大,能够增大数据量继续观察
对于q十、q18和q30,随着数据量增大,时间明显增大,需再深刻分析


有收获就点个「在看」吧 ▼
本文分享自微信公众号 - 老蒙大数据(simon_bigdata)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。