kyro序列化

一、序列化对比

在分布式系统中扮演着重要的角色,优化Spark程序时,首当其冲的就是对序列化方式的优化。Spark为使用者提供两种序列化方式:

  • Java Serialization: 默认的序列化方式。Spark内部是使用Java的序列化机制,ObjectOutputStream / ObjectInputStream,对象输入输出流机制,来进行序列化
  • Kryo Serialization: 相较于 Java Serialization 的方式,速度更快,空间占用更小,但并不支持所有的序列化格式,同时使用的时候需要注册class。spark-sql中默认使用的是kyro的序列化方式。

二、Kryo序列化机制,生效的场景

2.1、算子函数中使用到的外部变量

优化网络传输的性能,可以优化集群中内存的占用和消耗

2.2、持久化RDD时进行序列化,StorageLevel.MEMORY_ONLY_SER

持久化RDD,优化内存的占用和消耗;持久化RDD占用的内存越少,task执行的时候,创建的对象,就不至于频繁的占满内存,频繁发生GC。

2.3、shuffle

在进行stage间的task的shuffle操作时,节点与节点之间的task会互相大量通过网络拉取和传输文件,此时,这些数据既然通过网络传输,也是可能要序列化的,就会使用Kryo

三、Kyro的使用

3.1、配置

有两种配置方式

  • 在配置文件中,可以在spark-default.conf设置全局参数
  • 在代码中设置
sparkConf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")

3.2、注册, 也是就是为什么spark没有将kyro作为默认的序列化机制

sparkConf.registerKryoClasses(new Class[] {自定义的序列化的类});

3.2.1、如果你要序列化的对象比较大,可以增加参数spark.kryoserializer.buffer所设置的值。

3.2.2、弊端: 如果你没有注册需要序列化的class,Kyro依然可以照常工作,但会存储每个对象的全类名(full class name),这样的使用方式往往比默认的 Java serialization 还要浪费更多的空间。

3.2.3、可以设置 spark.kryo.registrationRequired 参数为 true,使用kyro时如果在应用中有类没有进行注册则会报错:

四、spark使用KryoRegistrator java代码示例

4.1、自定义序列化类

class Qualify implements Serializable

4.2、注册序列化类

import org.apache.spark.serializer.KryoRegistrator;

import com.esotericsoftware.kryo.Kryo;

public class MyRegistrator implements KryoRegistrator{
  
    public void registerClasses(Kryo arg0) {
        //注册序列化类
        arg0.register(Qualify.class);
    }
}

4.3、配置

 conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
 conf.set("spark.kryo.registrator", "com.chb.test.kyro.MyRegistrator");

五、问题

5.1、object not serializable (class: org.apache.hadoop.io.BytesWritable)

  spark操作返回的数据类型为BytesWriteable, 我有对返回数据进行其他操作(如, join),但是BytesWritable没有实现 java.io.Serializable 接口 , 所以运行过程中就会报错没有学历恶化

5.2、解决方式

5.2.1、指定如何序列化BytesWritable

手动指定

	conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    conf.registerKryoClasses(Array(classOf[org.apache.hadoop.io.BytesWritable]))

那么就是Kyro来序列化BytesWritable对象, 就可以在网络间传输了。

5.2.2、将BytesWritable转换成其他可序列化的对象

这种方法就是从BytesWritable 对象中抽取我们需要的数据,然后将它存储在其他可序列化的对象中,
如: 从BytesWritable 对象中抽取我们要的数据并转换成String,而 String 是实现 java.io.Serializable 接口的类,所以也可以解决上面的问题。

你可能感兴趣的:(#,spark)