Spark JVM调优 --GC

来源:互联网 发布:微电影后期软件 编辑:程序博客网 时间:2024/05/22 12:07

Spark发生垃圾回收的原理:

  GC:garbage collector 垃圾回收

executor是JVM中的服务进程。Spark任务运行的时候就是不断的在executor中创建对象。若JVM存不下对象了,就会触发GC(把不需要的对象清除)。
若内存中数据量较大,则可能会很频繁的发生GC,而GC本身很耗费性能,对Spark作业性能影响很大。
同时若数据量很大,那么GC一个涉及的数据量也很大,同样导致GC速度较慢。
除此之外,GC的时候是一条线程,GC运行的时候,会让Spark作业运行时候的那些工作线程停止让GC进程单独运行。会导致Spark作业性能影响较大。

垃圾回收过程
executor分为两部分老年代、新生代。
1. 新生代分为:Eden区、survivor1、survivor2
运行Spark任务会不断产生创建对象,对象会首先进入Eden区,Eden区存满,对象会进入survivor1区;若survivor1区也存满。就会发生minor GC。会在新生代中把不需要使用的对象进行回收。
2. 把还存活的、没被回收掉的对象放入survivor2区。之后,survivor1已经清空,接着survivor1和survivor2进行调换。
3. 若survivor2也不够用时,会把对象存入老年代中。(如果一个对象在新生代多次发生minor GC,还是没被回收,说明它是长时间存活的对象,就会把这些对象移到老年代中)
4. 若一直这么移动,老年代也存满,就会触发full GC(非常耗费资源)

不正常情况:若Eden区不够大,很可能出现大量的数据频繁进入survivor区,那么会频繁的进入老年代,full GC就会频繁的发生,会导致工作线程停止,直接印象spark作业运行。

JVM调优

发生full GC根本原因是内存不够用
垃圾回收的性能开销,是跟内存中的对象的数量,成正比的。
1)对于垃圾回收的性能问题,首先要做的就是,使用更高效的数据结构,比如array和string;
2)持久化rdd时,使用序列化的持久化级别,而且用Kryo序列化类库,这样,每个partition就只是一个对象——一个字节数组。
3)给Eden区域分配更大的空间,使用-Xmn即可,通常建议给Eden区域,预计大小的4/3;
如果使用的是HDFS文件,那么很好估计Eden区域大小,如果每个executor有4个task,然后每个hdfs压缩块解压缩后大小是3倍,此外每个hdfs块的大小是64M,那么Eden区域的预计大小就是:4 * 3 * 64MB,然后呢,再通过-Xmn参数,将Eden区域大小设置为4 * 3 * 64 * 4/3。

在使用大数据工具的时候,我们通常使用如下的工具:
Hadoop:HDFS (Namenode、Datanode)、YARN(ResourceManager、NodeManager)
Hbase:Hmaster、 HRegionserver
Spark : Master、 worker
全都是JVM进程(java虚拟机服务进程)

JVM体系:
这里写图片描述

stack栈

heap堆
整个JVM调优是围绕着堆内存去进行的
这里写图片描述

这里写图片描述
这里写图片描述
堆设置

GC算法
这里写图片描述
方法一:引用计数法
这里写图片描述
方法二:标记-清除算法
这里写图片描述
方法三:复制算法
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半
方法四:标记-整理算法
这里写图片描述
方法五:分代收集算法
这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。

系统线程划分

  1. 串行收集器
    使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器。当然,此收集器也可以用在小数据量(100M 左右)情况下的多处理器机器上。可以使用-XX:+UseSerialGC 打开。
  2. 并行收集器
    对年轻代进行并行垃圾回收,因此可以减少垃圾回收时间。一般在多线程多处理器机器上使用。使用-XX:+UseParallelGC .打开。年老代进行并行收集。如果年老代不使用并发收集的话,是使用单线程进行垃圾回收 ,因此会制约扩展能力。使用-XX:+UseParallelOldGC 打开。
    使用-XX:ParallelGCThreads= 设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等 。
    此收集器可以进行如下配置:
    最大垃圾回收暂停: 指定垃圾回收时的最长暂停时间,通过-XX:MaxGCPauseMillis= 指定。为毫秒.如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值 。设定此值可能会减少应用的吞吐量。
    吞吐量: 吞吐量为垃圾回收时间与非垃圾回收时间的比值 ,通过-XX:GCTimeRatio= 来设定,公式为1/(1+N) 。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。
  3. 并发收集器
    可以保证大部分工作都并发进行(应用不停止),垃圾回收只暂停很少的时间,此收集器适合对响应时间要求比较高的中、大规模应用。使用-XX:+UseConcMarkSweepGC 打开。
    并发收集器主要减少年老代的暂停时间,他在应用不停止的情况下使用独立的垃圾回收线程,跟踪可达对象。在每个年老代垃圾回收周期 中,在收集初期并发收集器会对整个应用进行简短的暂停,在收集中还会再暂停一次。第二次暂停会比第一次稍长,在此过程中多个线程同时进行垃圾回收工作。
    并发收集器使用处理器换来短暂的停顿时间 。在一个N个处理器的系统上,并发收集部分使用K/N 个可用处理器进行回收,一般情况下1<=K<=N/4 。
    在只有一个处理器的主机上使用并发收集器 ,设置为incremental mode 模式也可获得较短的停顿时间。
    浮动垃圾 :由于在应用运行的同时进行垃圾回收,所以有些垃圾可能在垃圾回收进行完成时产生,这样就造成了“Floating Garbage”,这些垃圾需要在下次垃圾回收周期时才能回收掉。所以,并发收集器一般需要20% 的预留空间用于这些浮动垃圾。
    Concurrent Mode Failure :并发收集器在应用运行时进行收集,所以需要保证堆在垃圾回收的这段时间有足够的空间供程序使用,否则,垃圾回收还未完成,堆空间先满了。这种情况下将会发生“并发模式失败”,此时整个应用将会暂停,进行垃圾回收。
    启动并发收集器 :因为并发收集在应用运行时进行收集,所以必须保证收集完成之前有足够的内存空间供程序使用,否则会出现“Concurrent Mode Failure”。通过设置-XX:CMSInitiatingOccupancyFraction= 指定还有多少剩余堆时开始执行并发收集

  4. 总结
    串行处理器:
    –适用情况:数据量比较小(100M左右);单处理器下并且对响应时间无要求的应用。
    –缺点:只能用于小型应用
    并行处理器:
    –适用情况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。
    –缺点:应用响应时间可能较长
    并发处理器:
    –适用情况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

Spark JVM 参数调优
-Xmx1073741824 -Xms1073741824
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:OnOutOfMemoryError=/usr/lib64/cmf/service/common/killparent.sh

-Xmx:最大堆大小
-Xms:初始堆大小
-XX:+UseConcMarkSweepGC
该标志首先是激活CMS收集器。默认HotSpot JVM使用的是并行收集器。

-XX:UseParNewGC
当使用CMS收集器时,该标志激活年轻代使用多线程并行执行垃圾回收。

-XX:+CMSConcurrentMTEnabled
当该标志被启用时,并发的CMS阶段将以多线程执行(因此,多个GC线程会与所有的应用程序线程并行工作)。该标志已经默认开启,如果顺序执行更好,这取决于所使用的硬件,多线程执行可以通过-XX:-CMSConcurremntMTEnabled禁用。
-XX:+CMSParallelRemarkEnabled:降低标记停顿

CMSInitiatingOccupancyFraction: 使用cms作为垃圾回收 使用70%后开始CMS收集

http://www.csdn.net/article/1970-01-01/2824823

vi spark-env.sh
这里写图片描述
cd sbin
./start-all.sh
jps
ps -ef | grep worker
这里写图片描述