Spark性能优化(2)—— 高性能序列化类库

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012292754/article/details/86241359

1 数据序列化

  • 在任何分布式的系统,序列化很重要,如果使用的序列化技术在执行序列化的时候很慢,或者序列化后数据还是很大,那么会导致分布式程序性能下降很多。所以 Spark 性能优化的第一步,就是进行序列化的性能优化;
  • Spark 默认会在一些地方对数据进行序列化,比如 shuffle。此外,如果用户的算子函数使用了外部的数据(比如 java 内置类型或者自定义类型),那么也需要对其序列化;
  • Spark 自身对于序列化的便捷性和性能进行了一个取舍。默认,Spark 倾向序列化的便捷性,使用了 Java 自身提供的序列化机制—— 基于 ObjectInputStreamObjectOutputStream 的序列化机制,因为这是 Java 原生提供的,方便使用。
  • 但是 Java 序列化机制的性能不高,序列化速度较慢,而且序列化后的数据还是比较大,会占用较多的内存。

2 Spark 提供的两种序列化机制

  1. Java 序列化机制

默认情况下,Spark使用Java 自身的 ObjectInputStreamOnjectOutputStream 机制进行对象的序列化。只要你的类实现了 Serializable 接口,那就可以序列化。而且 Java 序列化机制是提供了自定义序列化支持的,只要你实现 Externalizable 接口即可实现自己的更高性能的序列化算法。Java 序列化机智的速度比较慢,而且序列化后的数据占用的内存空间也比较大。

  1. Kryo 序列化机制

Kryo 序列化机制比 Java 序列化机制更快,而且序列化后数据占用的空间更小,通常比Java 序列化的数据占用的空间要小10倍。Kryo序列化机制之所以不是默认的,因为有些类型虽然实现了 Serializable 接口。但是它也不一定能够进行序列化,此外,如果你要得到最佳的性能,Kryo 还要求你在 Spark 应用程序中对所有你需要序列化的类型都进行注册。

3 如何使用 Kryo序列化

  • 首先SparkConf 设置一个参数,SparkConf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")。 这样Spark内部的一些操作,比如 Shuffle ,进行序列化的时候,就会使用 Kryo 类库
  • 使用 Kryo 时,它要求是需要序列化的类是要预先进行注册的,如果不注册,Kryo 必须时刻保存类型的全限定名,反而占用不少内存。Spark 默认对 Scala 中常用的类型自动注册了Kryo,都在 AllScalaRegistry
但是在自己的算子中,使用了外部自定义类型的对象,那么还是需要将其进行注册。
(实际,下面的写法是错误的,因为counter 不是共享的,所以累加的功能是无法实现的)
val counter  = new Counter();
val numbers = sc.parallelize(Array(1,2,3,4,5))
numbers.foreach(counter.add(_))

3.1 注册自定义类型

3.1.1 Scala 版本

val conf= new SparkConf().setMaster().setAppName()
conf.registerKryoClasses(Array(classOf[Counter]))
val sc  = new SparkContext(conf)

3.1.2 Java 版本

SparkConf conf = new SparkConf().setMaster().setAppName()
conf.registerKryoClasses(Counter.class)
JavaSparkContext sc = new JavaSparkContext(conf)

4 优化 Kryo类库的使用

  1. 优化缓存的大小
  • 如果注册的要序列化的自定义的类型本身特别大,比如包含了超过100个field,那么就会导致要序列化的对象太大。此时就需要对 Kryo 本身进行优化。因为 Kryo 内部的缓存可能不够存放那么大的 class 对象。此时就需要调用 SparkConf.set() 方法,设置 spark.kryoserializer.buffer.mb参数的值,将其调大;
  • 默认它的值是2,就是说最大能缓存 2M 对象,然后进行序列化。可以在必要的时候将其调大,比如设置为 10;
  1. 预先注册自定义类型
  • 虽然不注册自定义类型,Kryo 类库也可以正常工作,但是这样对于它要序列化的每个对象,都会保存一份它的全限定类名。此时反而会消耗大量内存。因此通常都建议预先注册好要序列化的自定义的类。

4 什么场景下使用 Kryo类库

  • 算子函数使用了外部的大数据的情况,比如说,我们在外部定义了一个封装了应用所有配置的对象,比如自定义了一个 MyConf 对象,里面包含了100M 的数据,然后在算子函数里,使用了这个外部的大对象
  • 此时,如果使用 Spark 默认的 Java 序列化机制来序列化这个外部的大对象,就会导致序列化速度缓慢,并且序列化以后的数据比较占用内存。因此,这种情况适合用 Kryo类库

猜你喜欢

转载自blog.csdn.net/u012292754/article/details/86241359
今日推荐