• spark 性能优化--调节并行度


    并行度:Spark 作业中,会根据 action 操作划分成多个 job,每个 job 中会根据 shuffle(宽依赖) 划分成多个 stage,每个 stage 会分配多个 task 去执行,各个 stage 划分的 task 数量就代表了 Spark 作业在该阶段(stage)并行度。 
     

    一,如果不调节并行度,导致并行度过低,会导致什么?

    假设,现在 spark-submit脚本里,给我们spark作业分配了足够多的资源,比如50个excutor ,每个excutor有10g内存,每个excutor,有3个core,最大并行度为50*3=150个task(executor数量*每个executor核数),150个执行完后,再换下一批150个task。
    如果task没有设置,或者设置的很少,比如就设置了100个task。50个excutor,每个excutor有3个cpu core,也就是说,Application任何一个stage运行时,都有总数在150个cpu core,可以并行运行。但是只有100个task,平均分配,每个excutor分配2个task,那么导致每个excutor 剩余一个cpu core 浪费资源。
    资源虽然足够,但是并行度没有与资源相匹配资源给多,会导致分配下去资源浪费掉。如果资源给少会降低性能(执行速度)。

    (分配资源策略--给application分配资源选择worker(executor),现在有两种策略)

    1.尽量的打散,即一个Application尽可能多的分配到不同的节点。这个可以通过设置spark.deploy.spreadOut来实现。默认值为true,即尽量的打散。(默认)
    2.尽量的集中,即一个Application尽量分配到尽可能少的节点。

    (spark性能优化--增加executor的内存量):

    1.如果需要对RDD进行cache,那么更多的内存,就可以缓存更多的数据,将更少的数据写入磁盘,甚至不写入磁盘。减少了磁盘IO。
    2.对于shuffle操作,reduce端,会需要内存来存放拉取的数据并进行聚合。如果内存不够,也会写入磁盘。如果给executor分配更多内存以后,就有更少的数据,需要写入磁盘,甚至不需要写入磁盘。减少了磁盘IO,提升了性能。
    3.对于task的执行,可能会创建很多对象。如果内存比较小,可能会频繁导致JVM堆内存满了,然后频繁GC,垃圾回收, GC和full GC。(速度很慢)。内存加大以后,带来更少的GC,垃圾回收,避免了速度变慢,速度变快了。

    二,怎么设置

    一般我们通过配置这些Spark运行参数:--num-executors,,--executor-memory, --execuor-cores 来进行调节并行度,如何正确配置参数达到最优性能而不使资源浪费了?

    三,理论引导

    当配置参数时,请遵循下表,将其推荐建议牢记于心

    Hadoop/Yarn/OS 守护进程:
    当利用一个集群管理器(比如YARN)运行spark程序时,存在一些守护进程运行在后台,比如NameNode,Secondary NameNode,DataNode,JobTracker和TaskTracker。
    因此,当确定num-executor时,我们需要确保有足够的cores(大约每个节点一个core)维持这些守护进程的平稳运行。

    Yarn ApplicationMaster (AM):
    ApplicationMaster的职责是:向ResourceManager协商资源,与NodeManager一同执行并监控containner及其资源消耗。如果程序运行在Spark-On-Yarn,我们需要预留一些资源给ApplicationMaster,AM大约需要1024MB的内存和一个Executor。

    HDFS吞吐:
    HDFS客户端会遇到大量并发线程的问题。 据观察,HDFS当达到全写入吞吐量时,需要每个executor执行约5个任务。 因此,最好控制每个executor中core的数目低于那个数字。

    内存开销:
    下图描绘了spark-yarn的内存使用情况:
    [图片上传失败...(image-fa6806-1536392056623)]
    图中注意两件事情:

           Full memory requested to yarn per executor =
              spark-executor-memory + spark.yarn.executor.memoryOverhead
          spark.yarn.executor.memoryOverhead = 
                Max(384MB, 7% of spark.executor-memory)

    所以,如果我们申请了每个executor的内存为20G时,对我们而言,AM将实际得到20G+ memoryOverhead = 20 + 7% * 20GB = ~23G内存。

    执行拥有太多内存的executor会产生过多的垃圾回收延迟
    执行过小的executor(举例而言,一个只有一核和仅仅足够内存跑一个task的executor),将会丢失在单个JVM中运行多任务的好处。

    四,开始实战

    **集群配置:**
    10个节点
    每个节点16核
    每个节点64G内存

    第一种方案:使用较小的executors
    Tiny executors表示一个executor配置一个core。下表描述了该方案下的参数配置。

    - '--num-executors' = '该方案下,每个executor配置一个core'
                                    = '集群中的core的总数'
                                    = '每个节点的core数目 * 集群中的节点数' 
                                    = 16 x 10 = 160
    - '--executor-cores' = 1 (每个executor一个core)
    - '--executor-memory' = '每个executor的内存'
                                        = '每个节点的内存/每个节点的executor数目'
                                        = 64GB/16 = 4GB
    分析:当一个executor只有一个core时,正如我们上面分析的,我们可能不能发挥在单个JVM上运行多任务的优势。
    此外,共享/缓存变量(如广播变量和累加器)将复制到节点的每个core,这里是16次。并且,我们没有为Hadoop / Yarn守护进程留下足够的内存开销,
    我们也没有计入ApplicationManager。因此,这不是一个好的方案!
     

    第二种方案:使用较大的executors
    Fat executors表示一个executor独占一个节点。下表描述了该方案下的参数配置:

    - `--num-executors` = `该方案下,一个executor独占一个节点`
                                    = `集群中的节点的数目`
                                    = 10
    - `--executor-cores` = `一个节点一个executor意味着每个executor独占节点中所 
                                       有的cores`
                                    = `节点中的core的数目`
                                    = 16
    - `--executor-memory` = `每个executor的内存`
                                        = `节点的内存/节点中executor的数目`
                                        = 64GB/1 = 64GB

    分析:每个executor独占16个核心,则ApplicationManager和守护程序进程则无法分配到core,并且,HDFS吞吐量会受到影响,导致过多的垃圾结果。 同样地,该方案不好!

    第三种方案:优化executors(推荐)

    考虑Linux运行及程序、Hadoop、Yarn等守护进程等,约占5%-10%,每台预留1核4G内存
    基于上述建议,我们给每个executor分配5个core => -- executor-cores = 5 (保证良好的HDFS吞吐)
    每个节点留一个core给Hadoop/Yarn守护进程 => 每个节点可用的core的数目 = 16 - 1
    所以,集群中总共可用的core的数目是 15 * 10 = 150
    可用的executor的数目 = (总的可用的core的数目 / 每个executor的core的数目)= 150 / 5 = 30
    留一个executor给ApplicationManager => --num-executors = 29
    每个节点的executor的数目 = 30 / 10 = 3
    每个节点留4G给Hadoop/Yarn守护进程 => 每个节点executor的内存 = (64-4) / 3 = 20GB
    计算堆外开销= 20GB * 7% ~ 1.4G,实际的 --executor-memory = 20 - 1.4 = 18.6GB
    因此,推荐的配置如下:29 executors, 18GB memory each and 5 cores

    另一种计算方式:

    每个executor进程分配核数5core(保证良好HDFS吞吐量)

    每台可用16 - 1 = 15core (留一个core给hadoop/yarn守护进程)

    每台可用64 - 4  = 60G (留4个G给hadoop/yarn守护进程)

    总核数15*10=150,总内存数60*10=600

    进程数150/5=30 num executor ,减去一,实际29executor(留一个executor给ApplicationManager)

    实际内存数600/29 = 20G,减去堆外开销,20*93%=18.6G

    因此,推荐的配置如下:29 executors, 18GB memory each and 5 cores

  • 相关阅读:
    比较重量(网易笔试题)
    抽象工厂模式
    简单工厂模式
    R语言dai xie
    Hadoop综合大作业
    hive基本操作与应用
    用mapreduce 处理气象数据集
    熟悉常用的HBase操作,编写MapReduce作业
    爬虫大作业
    第三章 熟悉常用的HDFS操作
  • 原文地址:https://www.cnblogs.com/chong-zuo3322/p/13127361.html
Copyright © 2020-2023  润新知