引发性能优化之使用高性能序列化类库

,,,如果使用序列化技术,在执行序列化操作的时候很慢或者是序列化之后的数据量还是很大,那么会让分布式应用程序性能下降很多,引发自身就会在一些地方对数据进行序列化,比如洗牌写磁盘,还有就是如果我们算子函数使用了外部数据,(比如Java内置类型,或者自定义类型)那么也需要让其可序列化。

,,,默认,火花使用了Java自身提供的序列化机制,基于objectoutputStream和objectinputstream,因为这种方式是Java原生提供的,很方便使用。但是Java序列化机制性能并不高,速度比较慢,序列化后的数据还是比较大,只要你的类实现了可序列化的接口,那么都是可以序列化的。

,,火花支持使用Kryo类型来进行序列化,比Java序列化机制更快,而且序列化后的数据量更小.Kryo序列化机制之所以不是默认序列化机制的原因是,有些类型虽然实现了Seriralizable接口,但是它也不一定能够进行序列化;此外,如果你要得到最佳的性能,Kryo还要求你在火花应用程序中,对所有你需要序列化的类型都进行注册,

,,,如果要使用Kryo序列化机制,首先要用SparkConf设置一个参数,使用新SparkConf()这里(“火花。序列化器”、“org.apache.spark.serializer.KryoSerializer”)即可,即将火花的序列化器设置为KryoSerializer。这样,火花在内部的一些操作,比如洗牌,进行序列化时,就会使用Kryo类库进行高性能,快速,更低内存占用量的序列化了。

,,使用Kryo时,它要求是需要序列化的类,是要预先进行注册的,以获得最佳性能,如果不注册的话,那么Kryo必须时刻保存类型的全限定名,反而占用不少内存.Spark默认是对Scala中常用的类型自动注册了Kryo的,都在AllScalaRegistry类中。

,,,但是,比如自己的算子中,使用了外部的自定义类型的对象,那么还是需要将其进行注册。

(实际上、下面的写法是错误的,因为计数器不是共享的,所以累加的功能是无法实现的)

val counter=新柜台();

val数字=sc.parallelize(数组(1、2、3、4、5))

数字。foreach (num=比;counter.add (num));

,,如果要注册自定义的类型,那么就使用如下的代码,即可:


Scala版本:

val相依=new SparkConf () .setMaster (…) .setAppName (…)

相依。registerKryoClasses(阵列(名为[计数器])classOf)

val sc=new SparkContext(参看)


Java版本:

SparkConf相依=new SparkConf () .setMaster (…) .setAppName (…)

conf.registerKryoClasses (Counter.class)

JavaSparkContext sc=new JavaSparkContext(参看)

优化Kryo类库的使用

1,优化缓存大小

如果注册的要序列化的自定义的类型,本身特别大,比如包含了超过100个。那么就会导致要序列化的对象过大。此时就需要对Kryo本身进行优化。因为Kryo内部的缓存可能不够存放那么大的类对象。此时就需要调用SparkConf.set()方法,设置spark.kryoserializer.buffer.mb参数的值,将其调大。

默认情况下它的值是2,就是说最大能缓存2 m的对象,然后进行序列化。可以在必要时将其调大。比如设置为10 .

2,预先注册自定义类型

虽然不注册自定义类型,Kryo类库也能正常工作,但是那样的话,对于它要序列化的每个对象,都会保存一份它的全限定类名。此时反而会耗费大量内存。因此通常都建议预先注册号要序列化的自定义的类。

在什么场景下使用Kryo序列化类库

,,首先,这里讨论的都是火花的一些普通的场景,一些特殊的场景,比如抽样的持久化

,,,那么,这里针对的Kryo序列化类库的使用场景,就是算子函数使用到了外部的大数据的情况,比如说吧,我们在外部定义了一个封装了应用所有配置的对象,比如自定义了一个MyConfiguration对象,里面包含了100的数据,然后,在算子函数里面,使用到了这个外部的大对象。

,,此时呢,如果默认情况下,让火花用java序列化机制来序列化这种外部的大对象,那么就会导致,序列化速度缓慢,并且序列化以后的数据还是比较大,比较占用内存空间。

因此,在这种情况下,比较适合,切换到Kryo序列化类库,来对外部的大对象进行序列化操作。一是,序列化速度会变快;二是,会减少序列化后的数据占用的内存空间。


引发性能优化之使用高性能序列化类库