java.io.NotSerializableException: org.apache.kafka.clients.consumer.ConsumerRecord

問題

如下代碼報錯 

JavaInputDStream<ConsumerRecord<Object, Object>> stream =
		  KafkaUtils.createDirectStream(
		    streamingContext,
		    LocationStrategies.PreferConsistent(),
		    ConsumerStrategies.Subscribe(topics, kafkaParams)
		  );
java.io.NotSerializableException: org.apache.kafka.clients.consumer.ConsumerRecord
Serialization stack:
	- object not serializable (class: org.apache.kafka.clients.consumer.ConsumerRecord, value: ConsumerRecord(topic = topic01, partition = 0, offset = 33074, CreateTime = -1, serialized key size = -1, serialized value size = 8, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = aviation))
	- element of array (index: 0)
	- array (class [Lorg.apache.kafka.clients.consumer.ConsumerRecord;, size 11)
	at org.apache.spark.serializer.SerializationDebugger$.improveException(SerializationDebugger.scala:40)
	at org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:46)
	at org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:100)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:383)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

 

解決方法

1、將ConsumerRecord類註冊爲使用Kyro序列化

		 SparkConf sparkConf = new SparkConf().setAppName("JavaFlumeEventCount")
				 .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
		 sparkConf.registerKryoClasses((Class<?>[]) Arrays.asList(ConsumerRecord.class).toArray());

 

知識補充

spark的兩種常用序列化方式

序列化在分佈式系統中扮演着重要的角色,優化Spark程序時,首當其衝的就是對序列化方式的優化。Spark爲使用者提供兩種序列化方式:

Java serialization: 默認的序列化方式。

Kryo serialization: 相較於 Java serialization 的方式,速度更快,空間佔用更小,但並不支持所有的序列化格式,同時使用的時候需要註冊class。spark-sql中默認使用的是kyro的序列化方式。

下文將會講解kryo的使用方式並對比性能。

Kyro序列化步驟 

一、如果需要多個類都使用Kyro序列化,可以自定義一個註冊類,同時進行多個類的註冊,如下
    主要的使用過程就三步:
    1.設置序列化使用的庫
        conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");  //使用Kryo序列化庫
    2.在該庫中註冊用戶定義的類型
        conf.set("spark.kryo.registrator", toKryoRegistrator.class.getName());       //在Kryo序列化庫中註冊自定義的類集合
    3.在自定義類中實現KryoRegistrator接口的registerClasses方法.要求自定義類實現Serializable,即下面的temp1、temp2類
        public static class toKryoRegistrator implements KryoRegistrator {
            public void registerClasses(Kryo kryo) {
                kryo.register(tmp1.class, new FieldSerializer(kryo, tmp1.class));  //在Kryo序列化庫中註冊自定義的類
                kryo.register(tmp2.class, new FieldSerializer(kryo, tmp2.class));  //在Kryo序列化庫中註冊自定義的類
            }
        }
        
二、如果只是註冊一個類使用Kyro序列化,直接使用如下即可
    1.設置序列化使用的庫
        conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");  //使用Kryo序列化庫
    2.註冊序列化類
        conf.registerKryoClasses((Class<?>[]) Arrays.asList(ConsumerRecord.class).toArray());

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章