使用JMC工具对spark 程序调优(三)

上文通过一个例子来说明JMC的用处。实际上,例子中使用的的还是JMC极小的一部分功能。
另一方面,笔者也对JMC进行了一些摸索,感觉对JMC的应用,还不是很熟练。

从笔者的感觉,虽然jmc可查看的参数很多,但它却并不是为spark平台准备的。用它监控spark平台,问题有2个:
(1)jmc监控的参数与spark的参数没有直接关系。
(2)把监控的参数状态同具体代码结合起来,仍需要比较强的分析能力。

其实,笔者一直在寻找一些工具,能够直接得出spark优化的结果好坏,与spark的内层机理运行过程。

就笔者而言,spark平台调优,主要在以下几个方面,如图:
使用JMC工具对spark 程序调优(三)_第1张图片

如果非要有个优先顺序,则按照从上到下的顺序比较好。

先来讨论下spark的重要参数。一般在spark程序启动配置如下:

./bin/spark-submit \
  --master yarn-cluster \
  --num-executors 100 \
  --executor-memory 6G \
  --executor-cores 4 \
  --driver-memory 1G \
  --conf spark.default.parallelism=1000 \
  --conf spark.storage.memoryFraction=0.5 \
  --conf spark.shuffle.memoryFraction=0.3 \

除此之外,还有很多运行时环境,比如:yarn 的分配调度等等。

还有一个显而易见的问题:就是一个集群通常集成好几种平台组件,比如hadoop,zookeeper,hbase,redis等组件,这让spark调优增加难度。

先抛开这些问题,来具体讨论下笔者认为的几个重要点。
首先是jvm优化。
jvm由Non-Heap 和Heap 构成。Non-Heap多是一些固定的分配,因此,我们只关注Heap区。

Heap 分成:Eden、Survivor 和Tenured 三种类型区域,其基本的管理过程是:

创建的新对象开始放在Eden 区,Minor GC后剩余的对象放入Survivor;Survivor 里面对象过了一段时间好,依然没有被回收的话,那么这些对象就放入Tenured 区;当Tenured 区满了以后,就会触发Full GC 来全局回收空间。从GC 管理角度,Heap 分成Young Gen(年轻代),它包括1 个Eden 和2 个Survivor 区,建立年轻代的目的是尽可能快的回收那些生命周期短的对象,所以针对这个代,特别建立一个Minor GC 来专门对待;另外一个就是Old Gen(年老代),它包括1 个Tenured 区,那些在年轻代经过多次Minor GC 就不能回收的对象就往年老代扔,等年老代的Tenured 区满了,JVM 就会进行Full GC 处理。值得说明的是,Full GC 作用范围包括:年轻代、年老代和Non-Heap 的持久代(Perm Gen)。
由于Full GC 一般较为耗时(内存越大,GC 耗时越多),而且在GC 过程中整个JVM 会临时终止服务,所以为了高性能,合理调整年轻代、年老代的大小,让对象尽量在年轻代就被Minor GC 回收,减少Full GC 出现的机会。

从上面一段话中可以总结以下3点:

  1. 年轻代包含Eden,Survivor;老年代包含Tenured。年轻代进入老年代。
  2. 回收分2种,Minor GC 和Full GC。也就是小gc和大gc。
  3. 尽量做小GC。

在上一个例子中,我们对gc回收主要有2个思路:

  1. 加快年轻代进入老年代。
  2. 加快老年代的full gc。

第一点没问题,第二点,需要注意的地方是,Full GC对CPU的占用。如果cpu够好,那也问题不大。如果对cpu占用有顾虑,在年老代gc配置中,主要有-XX:+UseParallelOldGC和-XX:+UseConcMarkSweepGC这两种,ParallelOldGC吞吐率较大,ConcMarkSweepGC延迟较低。对吞吐率要求较低,可以设置-XX:CMSInitiatingOccupancyFraction,即年老代内存使用率达到什么比例时触发CMS。

未完待续。。。

你可能感兴趣的:(大数据,集群,spark,调优,jmc)