Kryo序列化与Java序列化

1.序列化在Spark中的用处

  • 在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输
  • 将自定义的类型作为RDD的泛型类型时(比如JavaRDD,Student是自定义类型),所有自定义类型对象,都会进行序列化。因此这种情况下,也要求自定义的类必须实现Serializable接口。

  • 使用可序列化的持久化策略时(比如MEMORY_ONLY_SER),Spark会将RDD中的每个partition都序列化成一个大的字节数组。

2.Java序列化与kryo序列化对比

  • Java序列化:采用objectOutputStream对对象进行序列化,任何的类实现一个 java.io.Serializable接口都可以进行序列化,尽管Java序列化操作十分灵活,但是却十分缓慢,会产生更大的序列化类

  • Kryo序列化:kryo序列化更快且比Java占用空间更小。但是并不支持所有序列化类,需要事先在应用程序中注册类

3.kryo启动方式

在conf中配置:

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

4.调优

  • spark.kryoserializer.buffer 这个是core中kryo缓存的大小,每个core一个,默认64K

  • spark.kryoserializer.buffer.max 这个是缓存的最大大小,默认为64M,序列化的类最大不可超过2G

5.测试

  • 普通不序列化的MEMORY_ONLY
val persons=new ArrayBuffer[Person]
for(i<-1 to 1000000)
{

persons+=(Person("name"+i,10+i,"male","haerbin"))
}
val personrdd=sc.parallelize(persons)
personrdd.persist(StorageLevel.MEMORY_ONLY)
personrdd.count()

结果:95.3M

  • 使用Java序列化的MEMORY_ONLY_SER
val persons=new ArrayBuffer[Person]
for(i<-1 to 1000000)
{
persons+=(Person("name"+i,10+i,"male","haerbin"))
}
val personrdd=sc.parallelize(persons)
personrdd.persist(StorageLevel.MEMORY_ONLY_SER)
personrdd.count()

总结:39.8M,效果还是可以的

  • kryo的未注册类的MEMORY_ONLY_SER
val persons=new ArrayBuffer[Person]
for(i<-1 to 1000000)
{
persons+=(Person("name"+i,10+i,"male","haerbin"))
}
val personrdd=sc.parallelize(persons)
personrdd.persist(StorageLevel.MEMORY_ONLY_SER)
personrdd.count()

总结:119.1M,之所以会发生这种情况,是因为没有注册类,所以kryo就将所有的类进行操作,所有导致占用很大内存

  • 使用kryo注册类,然后打包到集群运行(这种方式命令行看不到效果)
sc.getConf.registerKryoClasses(Array(classOf[Person]))

val persons=new ArrayBuffer[Person]
for(i<-1 to 1000000)
{
persons+=(Person("name"+i,10+i,"male","haerbin"))
}
val personrdd=sc.parallelize(persons)
personrdd.persist(StorageLevel.MEMORY_ONLY_SER)

使用submit提交jar包
--class sparkcore.SerializerApp \
--name SerializerApp \
--master yarn \
 /home/hadoop/lib2/scala6-1.0.jar 

总结 :27.5M,结果显而易见,kryo效果更好

你可能感兴趣的:(spark)