問題
如下代碼報錯
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());