大数据IMF传奇行动绝密课程第48课:Spark性能优化第四季

来源:互联网 发布:ghgvh软件下载 编辑:程序博客网 时间:2024/04/28 11:17

Spark性能优化第四季

1、序列化
2、JVM性能调优
一、Spark性能调优之序列化
1、之所以进行序列化,最重要的原因是内存空间有限(减少GC的压力,最大化的避免Full GC的产生,因为一旦产生Full GC,则整个Task处于停止状态)、减少磁盘IO的压力,减少网络IO的压力
2、什么时候会必要的产生序列化和反序列化呢?发生磁盘IO和网络通信的时候会序列化和反序列化;更为重要的考虑序列化和反序列化的时候有另外两种情况:
a)persist(Checkpoint)的时候必须考虑序列化和反序列化,例如说cache到内存的时候只能使用JVM分配的60%的内存空间,此时好的序列化机制就至关重要了
b)编程的时候,使用算子的函数操作如果传入了外部数据就必须序列化和反序列化

#以下代码是错误的val person = new Person()rdd.map(item => person.add(item))

3、强烈建议使用Kryo序列化器进行序列化和反序列化;Spark默认情况下不是使用的Kyro而是Java自带的序列化器ObjectInputStream和ObjectOutputStream(主要是考虑了方便性或者通用性),默认情况下如果自定义了RDD中数据的类型则必须实现serializable接口,当然也可以实现自己的序列化接口Externalizable来实现更加高效的Java序列化算法;采用默认的ObjectInputStream和ObjectOutputStream会导致序列化后的数据占用大量的内存、磁盘或网络,并且在序列化和反序列化的时候比较消耗CPU
4、强烈推荐大家采用Kryo序列化机制,Spark下使用Kryo序列化机制会比Java默认的序列化机制更加节省空间(节省近10倍的空间)以及消耗更少的CPU,强烈建议在一切情况下尽可能使用Kryo序列化机制。
5、使用Kryo的两种方式:
a)在spark-defaults.conf中配置
b)在程序的SparkConf中配置。

conf.set(spark.serializer org.apache.spark.serializer.KryoSerializer)

使用Kryo可以更加快速,更低存储空间占用量以及更高性能的方式来进行序列化。
6、Spark中Scala常用的类型自动的通过AllScalaRegistry注册给了Kryo进行序列化管理;
7、如果是自定义的类型必须注册给序列化器,例如

conf.set(spark.serializer org.apache.spark.serializer.KryoSerializer)conf.registryKryoClass(Array(classOf[Person]))val person = new Person()rdd.map(item => person.add(item))

8、Kryo在序列化的时候缓存空间默认大小是2MB,可以根据具体的业务模型调整该大小,具体方式:
设置spark.kryoserializer.buffer为10MB等
9、在使用Kryo时,强烈建议注册时写完整的包名和类名,否则的话每次序列化的时候都会保存一份整个包名和类名的完整信息,这就会不必要的消耗内存空间
二、Spark JVM性能调优
1、好消息是Spark的钨丝计划是用来专门解决JVM性能问题的,不好的消息是至少在Spark 2.0以前钨丝计划功能不稳定且只能在特定情况下发生作用,也就是说包括Spark 1.6.0在内的Spark及其以前的版本我们大多数情况下没有使用钨丝计划的功能,所以此时就必须关注JVM性能调优;
2、JVM性能调优的关键是调优GC。为什么GC如此重要?主要是因为Spark热衷于RDD的持久化。GC本身的性能开销是和数据量成正比的
3、初步可以考虑是尽量多的使用array和String,并且在序列化机制方面尽可能地采用Kryo,让每个partition都成为字节数组;
4、监视GC的基本方式有两种
a)配置

spark.executor.extraJavaOptions = -verbose:gc -XX:-PrintGCDetails -XX:+ PrintGCDateTimeStamps

b)SparkUI
5、Spark在默认情况下使用60%的空间来进行Cache缓存RDD的内容,也就是说Task在执行的时候只能使用剩下的40%;如果空间不够用就会(频繁)触发GC
可以设置spark.memory.fraction参数来进行调整空间的使用,例如降低Cache空间,让Task使用更多的空间来创建对象和完成计算;
再一次强烈建议对RDD进行Cache的时候使用Kryo序列化机制,从而给Task分配更大的空间来顺利完成计算(避免频繁的GC)
6、因为在老年代空间满的时候会发生Full GC操作,而老年代空间中基本都是活的比较久的对象(经历数次GC依旧存在),此时会停下所有程序线程,进行Full GC,对Old区中的对象进行整理,严重影响性能;此时可以考虑:
a)设置spark.memory.fraction参数来进行调整空间的使用从而给年轻代更多的空间用于存放短时间的存活的对象;
b)-Xmn调整Eden区域;RDD中操作的对象和数据进行大小评估,如果在HDFS上解压后一般体积可能会变成原有体积的3倍左右;根据数据的大小来设置Eden;如果有10个Task,每个Task处理的HDFS上的数据是128MB,则需要设置-Xmn为10*128*3*4/3的大小。
c)-XX:SupervisorRatio 在Eden不出问题的情况下适当调大s1、s2的大小
d)-XX:NewRatio

0 0
原创粉丝点击