序列化和自定义Spark RDD类

时间:2015-03-06 23:58:33

标签: scala hadoop serialization apache-spark rdd

我在Scala中编写自定义Spark RDD实现,并且我正在使用Spark shell调试我的实现。我现在的目标是获得:

customRDD.count

没有异常就能成功。现在这就是我得到的:

15/03/06 23:02:32 INFO TaskSchedulerImpl: Adding task set 0.0 with 1 tasks
15/03/06 23:02:32 ERROR TaskSetManager: Failed to serialize task 0, not attempting to retry it.
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.spark.serializer.SerializationDebugger$ObjectStreamClassMethods$.getObjFieldValues$extension(SerializationDebugger.scala:240)

...

Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
    at java.io.ObjectStreamClass$FieldReflector.getObjFieldValues(ObjectStreamClass.java:2050)
    at java.io.ObjectStreamClass.getObjFieldValues(ObjectStreamClass.java:1252)
    ... 45 more

&#34;未能序列化任务0&#34;引起我的注意。我没有对我所做的事情有customRDD.count的精彩描述,并且非常不清楚 无法序列化。< / p>

我的自定义RDD包含:

  • 自定义RDD类
  • 自定义分区类
  • custom(scala)Iterator类

My Spark shell会话如下所示:

import custom.rdd.stuff
import org.apache.spark.SparkContext

val conf = sc.getConf
conf.set(custom, parameters)
sc.stop
sc2 = new SparkContext(conf)
val mapOfThings: Map[String, String] = ...
myRdd = customRDD(sc2, mapOfStuff)
myRdd.count

... (exception output) ...

我想知道的是:

  • 为了创建自定义RDD类,需要做什么&#34; serializable&#34;?
  • 就Spark而言,&#34;可序列化&#34;是什么意思?这类似于Java&#34; Serializable&#34;?
  • 从我的RDD迭代器返回的所有数据(由compute方法返回)是否也需要序列化?

非常感谢您对此问题的任何澄清。

3 个答案:

答案 0 :(得分:6)

在Spark上下文上执行的代码必须存在于指示执行任务的工作节点的同一进程边界内。这意味着必须注意确保RDD自定义中引用的任何对象或值都是可序列化的。如果对象是不可序列化的,那么您需要确保它们的范围正确,以便每个分区都有该对象的新实例。

基本上,您不能共享Spark驱动程序上声明的对象的非可序列化实例,并期望将其状态复制到群集上的其他节点。

这是一个无法序列化非序列化对象的示例:

NotSerializable notSerializable = new NotSerializable();
JavaRDD<String> rdd = sc.textFile("/tmp/myfile");

rdd.map(s -> notSerializable.doSomething(s)).collect();

下面的示例可以正常工作,因为它位于lambda的上下文中,它可以正确地分发到多个分区,而无需序列化非可序列化对象的实例的状态。这也适用于作为RDD定制(如果有)的一部分引用的非可序列化传递依赖项。

rdd.forEachPartition(iter -> {
  NotSerializable notSerializable = new NotSerializable();

  // ...Now process iter
});

请点击此处了解详情:http://databricks.gitbooks.io/databricks-spark-knowledge-base/content/troubleshooting/javaionotserializableexception.html

答案 1 :(得分:4)

除了Kenny的解释,我建议你打开序列化调试,看看是什么导致了这个问题。通常只能通过查看代码才能弄明白这一点。

-Dsun.io.serialization.extendedDebugInfo=true

答案 2 :(得分:0)

问题是你在customRdd方法中传递SparkContex(Boiler plate)(customRDD(sc2,mapOfStuff))。确保你的类也序列化了SparkContext。