美文网首页大数据相关sparkSpark & Flink
Spark 性能调优--资源调优

Spark 性能调优--资源调优

作者: Alex90 | 来源:发表于2018-01-05 15:00 被阅读115次

    资源调优

    在开发完Spark作业之后,就该为作业配置合适的资源了。Spark的资源参数,基本都可以在spark-submit命令中作为参数设置

    Spark作业基本运行原理

    Spark作业基本运行原理
    1. spark-submit提交一个Spark作业之后,这个作业就会启动一个对应的Driver进程
    2. 根据你使用的部署模式(deploy-mode:client/cluster)不同,Driver进程可能在本地启动,也可能在集群中某个工作节点上启动
    3. Driver进程本身会根据我们设置的参数,占有一定数量的内存和CPU Core
    4. Driver进程要做的第一件事情,就是向集群管理器(可以是Spark Standalone集群,也可以是YARN)申请运行Spark作业需要使用的资源。资源指的就是Executor进程。在各个工作节点上,启动一定数量的Executor进程,每个Executor进程都占有一定数量的内存和CPU Core
    5. 在申请到了作业执行所需的资源之后,Driver进程就会开始调度和执行我们编写的作业代码了
    6. Driver进程会将我们编写的Spark作业代码分拆为多个Stage,每个Stage执行一部分代码片段,并为每个Stage创建一批Task,然后将这些Task分配到各个Executor进程中执行
    7. Task是最小的计算单元,负责执行一模一样的计算逻辑(也就是我们编写的某个代码片段),只是每个Task处理的数据不同而已。一个Stage的所有Task都执行完毕之后,会在各个节点本地的磁盘文件中写入计算中间结果,然后Driver就会调度运行下一个Stage。下一个Stage的Task的输入数据就是上一个Stage输出的中间结果
    8. Spark是根据Shuffle类算子来进行Stage的划分,Shuffle算子执行之前的代码会被划分为一个Stage

    Executor的内存主要分为三块
    - 第一块是让task执行我们自己编写的代码时使用,默认是占Executor总内存的20%
    - 第二块是让Task通过Shuffle过程拉取了上一个Stage的Task的输出后,进行聚合等操作时使用,默认也是占Executor总内存的20%
    - 第三块是让RDD持久化时使用,默认占Executor总内存的60%
    参考Spark内存架构

    Task的执行速度是跟每个Executor进程的CPU Core数量有直接关系的。一个CPU Core同一时间只能执行一个线程。而每个Executor进程上分配到的多个Task,都是以每个Task一条线程的方式,多线程并发运行的。如果CPU Core数量比较充足,而且分配到的Task数量比较合理,那么通常来说,可以比较快速和高效地执行完这些Task线程


    资源参数调优

    num-executors
    设置Spark作业总共要用多少个Executor进程来执行
    Driver在向YARN集群管理器申请资源时,YARN集群管理器会尽可能按照你的设置来在集群的各个工作节点上,启动相应数量的Executor进程

    每个Spark作业的运行一般设置50~100个左右(根据集群的规模)的Executor进程比较合适,设置太少或太多的Executor进程都不好。设置的太少,无法充分利用集群资源;设置的太多的话,大部分队列可能无法给予充分的资源

    executor-memory
    设置每个Executor进程的内存
    Executor内存的大小,很多时候直接决定了Spark作业的性能,而且跟常见的JVM OOM异常,也有直接的关联

    每个Executor进程的内存设置4G~8G较为合适,num-executors乘以executor-memory,是不能超过队列的最大内存量的,Spark集群可以设置每个executor最多使用的内存大小。如果你是跟团队里其他人共享这个资源队列,那么申请的内存量最好不要超过资源队列最大总内存的1/3~1/2

    executor-cores
    设置每个Executor进程的CPU core数量
    决定了每个Executor进程并行执行task线程的能力

    数量设置为2~4个较为合适,依据资源队列的最大CPU Core限制是多少,再依据设置的Executor数量,来决定每个Executor进程可以分配到几个CPU Core

    driver-memory
    设置Driver进程的内存
    Driver的内存通常来说不设置,或者设置1G左右应该就够了

    如果需要使用 collect 算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM内存溢出的问题

    spark.default.parallelism
    设置每个stage的默认task数量
    不去设置这个参数,那么Spark根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task,通常来说,Spark默认设置的数量是偏少的

    设置该参数为num-executors * executor-cores的2~3倍较为合适
    如果task数量偏少的话,Executor进程可能根本就没有task执行,也就是白白浪费了资源

    spark.storage.memoryFraction
    设置RDD持久化数据在Executor内存中能占的比例,默认是0.6
    根据你选择的不同的持久化策略,如果内存不够时,可能数据就不会持久化,或者数据会写入磁盘

    如果Spark作业中,有较多的RDD持久化操作,该参数的值可以适当提高一些
    如果Spark作业中的Shuffle类操作比较多,而持久化操作比较少,那么这个参数的值适当降低一些比较合适
    如果发现作业由于频繁的GC导致运行缓慢(通过Spark WebUI可以观察到作业的GC耗时),意味着Task执行用户代码的内存不够用,那么同样建议调低这个参数的值

    spark.shuffle.memoryFraction
    设置Shuffle过程中一个task拉取到上个Stage的Task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2
    Shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地降低性能

    如果Spark作业中的RDD持久化操作较少,Shuffle操作较多时,建议降低持久化操作的内存占比,提高Shuffle操作的内存占比比例
    如果发现作业由于频繁的GC导致运行缓慢,意味着Task执行用户代码的内存不够用,那么同样建议调低这个参数的值



    示例

    #args : 
    /usr/local/spark/bin/spark-submit --class Process \
    --master yarn-cluster \
    --name Process \
    --queue fetech \
    --num-executors 20 \
    --driver-memory 5g \
    --executor-memory 4g \
    --executor-cores 2 \
    --conf spark.default.parallelism=500 \
    --conf spark.storage.memoryFraction=0.5 \
    /process.jar $1 $2 $3 $4
    

    相关文章

      网友评论

        本文标题:Spark 性能调优--资源调优

        本文链接:https://www.haomeiwen.com/subject/eaqsnxtx.html