Spark性能优化

主要针对内存的使用调优

Spark性能优化的技术

  1. 使用高性能序列化类库
  2. 优化数据结构
  3. 对于多次使用的RDD进行持久化、checkpoint
  4. 持久化级别:MEMORY_ONLY --> MEMORY_ONLY_SER序列化
  5. Java虚拟机垃圾回收调优
  6. Shuffle调优

一·、判断Spark内存使用

首先要看到内存使用情况,才能进行针对性的优化

(1)内存花费

  1. 每个Java对象,都有一个对象头,占用16字节,包含一些对象的元信息,比如指向它的类的指针。如果对象本身很小,比如int,但是他的对象头比对象自己还大
  2. Java的String对象,会比它内存的原始数据,多出40个字节。String内部使用的char数组来保存内部的字符串序列,并且还要保存诸如输出长度之类的信息。char使用的是UTF-16编码,每个字符会占2个字节。比如,包含10个字符的String,2*10+30=60字节
  3. Java中的集合类型,比如HashMap和LinkedList,内部使用链表数据结构。链表中的每个数据,使用Entry对象包装。Entry对象,不光有对象头,还有只想下一个Entry的指针,占用8字节
  4. 元素类型为原始数据类型(int),内部通常会使用原始数据类型的包装类型(Integer)来存储元素
  1. (2)判断内存消耗情况
  1. 设置RDD的并行度(parellelize和textFile两种方法创建RDD,在这两个方法中,传入第二个参数,设置RDD的partition数量。在SparkConfig中设置一个参数:spark.default.parallelism可以统一设置这个application中所有RDD的partition数量)
  2. 将RDD缓存
  3. 观察日志:driver日志(在Spark的work文件夹下)
  4. 将这个MemoryStore内存信息相加,就是RDD内存

二·、使用高性能序列化类库

  1. 1、数据序列化

数据序列化,就是将对象或者数据结构,转换成特定的格式,使其可在网络中传输,或存储在内存或文件中

反序列化,就是相反的操作,将对象从序列化数据中还原出来

序列化后的数据格式,可以是二进制,xml,json等任何格式

对象、数据序列化的重点在于数据的交换与传输

在任何分布式系统中,序列化都是扮演着一个重要的角色

如果使用的序列化技术,操作很慢,或者序列化后的数据量还是很大、会让分布式系统应用程序性能下降很多,所以Spark性能优化的第一步,就是进行序列化的性能优化

Spark自身默认会在一些地方对数据进行序列化,比如Shuffle。另外,我们使用了外部数据(自定义类型),也要让其可序列化

默认情况下:Spark倾向于序列化的便捷性,使用了Java自身提供的序列化机制,很方便使用。但是,Java序列化机制性能不高,序列化速度慢,序列化数据较大,比较占用内存空间

  1. 2、kryo

Spark支持使用kryo类库来进行序列化

速度快,占用空间更小,比Java序列化数据占用空间小10倍

  1. 3、使用kryo序列化机制

(1)设置Spark conf

spark.master spark://6.7.8.9:7077

spark.executor.memory 4g

spark.eventLog.enabled true

spark.serializer org.apache.spark.serializer.KryoSerializer

(2)使用kryo,需要序列化的类,提前注册,以获得高性能

conf.registerKryoClasses(Array(classOf[Count],...))

  1. 4、kryo类库的优化
  1. 优化缓存大小(如果注册的自定义类型,本身特别大(100个字段),会导致要序列化的对象太大。此时需要对kyro本身进行优化。因为kryo内部的缓存,可能不能存放这么大的class对象。设置spark.kryoserializer.buffer.max参数,将其调大)
  2. 预先注册自定义类型(虽然不注册自定义类型,kryo也可以正常工作,但会保存一份他的全限定类名,耗费内存。推荐预先注册要序列化的自定义类型)

三、优化数据结构

概述

要减少内存的消耗,除了使用高效的序列化类库外,还要优化数据结构,避免Java语法特性中所导致的额外内存开销

核心:优化算子函数内部使用到的局部数据或算子函数外部的数据

目的:减少对内存的消耗和占用

做法
  1. 优先使用数组以及字符串,而不是集合类(优先使用Array,而不是ArrayList、LinkedList、HashMap),使用int[]会比List节省内存
  2. 将对象转换成字符串
  3. 避免使用多层嵌套对象结构
  4. 对于能够避免的场景,尽量使用int代替String

四、Java虚拟机的调优

一·、概述

如果在持久化RDD的时候,持久化了大量的数据,那么Java虚拟机的垃圾回收就可能成为一个瓶颈

Java虚拟机会定期进行垃圾回收,此时会追踪所有Java对象,并且在垃圾回收时,找到那些已经不再使用的对象,清理旧对象,给新对象腾出空间

垃圾回收的性能开销,与内存中的对象数量成正比

做Java虚拟机调优之前,需做好前面的调优工作,才有意义

二、Spark GC原理

spark数据量大于内存 spark 处理10g数据_spark数据量大于内存

三、监测垃圾回收

监测多久进行一次垃圾回收一级耗费的时间等等

spark-submit脚本中,添加--conf "spark.executor.extraJavaOptions=-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimesStamps"

worker日志:spark下的logs文件夹

driver日志:spark下的worker文件夹

四、优化Executor内存比例

目的:减少GC次数

对于GC调优来说,最重要的就是调节,RDD的缓存占用空间与算子执行时创建对象所占用的内存空间的比例

对于默认情况,Spark使用每个Executor 60%的内存空间来缓存RDD,在task运行期间所创建的对象,只有40%内存空间来存放

配置:conf.set("spark.storage.memoryFraction",0.5)

spark数据量大于内存 spark 处理10g数据_Java_02