大数据-Spark性能优化

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。另外,我们使用了外部数据(自定义类型),也要让其可序列化

          扫描二维码关注公众号,回复: 10829909 查看本文章

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

          2、kryo

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

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

          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],...))

          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-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)

在这里插入图片描述

发布了131 篇原创文章 · 获赞 12 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/JavaDestiny/article/details/97962703