2016-02-23 30 views
-1

只有一个NotSerializableException我不明白。使用Spark 1.5.0启动EMR集群,然后输入shell spark-shell --master local(如果您选择yarn-client而不是local,则不会产生任何影响)。为什么spark-shell吐出NotSerializableException而sbt控制台没有?

然后运行下面的代码:

class MaybeSerializable() { 
    def add(i: Int) = i + 1 
} 

val foo = new MaybeSerializable() 

sc.makeRDD(1 to 1000).map(foo.add).reduce(_ + _) 

我答应你,就会造成org.apache.spark.SparkException: Task not serializable

现在创建使用星火"org.apache.spark" %% "spark-core" % "1.5.0"相同版本的SBT项目,并进入sbt console,然后运行

import org.apache.spark.SparkContext 

val sc = new SparkContext("local", "shell") 

class MaybeSerializable() { 
    def add(i: Int) = i + 1 
} 

val foo = new MaybeSerializable() 

sc.makeRDD(1 to 1000).map(foo.add).reduce(_ + _) 

我向你保证它会起作用!没有例外!

如果有人能解释这一点,我会非常高兴。

回答

0

关于行为的不一致性,我不是Spark专家,但我会说在第一种情况下,当使用Yarn EMR时,整个“MaybeSerializable”类会被肯定地序列化并被发送到执行者由司机。由于它不是可序列化的,因此会出现“NotSerializableException”异常。

另一方面,在第二种情况下,我不太确定班级是否被序列化,这就是为什么你没有得到例外。底层架构正在推动或不需要序列化。当你使用sbt时,如果驱动程序没有将任何序列化的类发送到任何进程,我不会感到惊讶。在这种情况下,因为它不是必需的,所以如果这个类是可序列化的也没关系。

我可以在独立的计算机中重现第一个问题,并且通过这种方式使类可序列化:“class MaybeSerializable()extends Serializable”。这是我使用(和/或匿名函数)确保我的代码将以任何集群类型运行并且序列化行为在集群中保持一致的最佳实践。

我希望它有帮助。

+0

我建议避免使用'extends Serializable'和用例类来确保数据和函数之间清晰分离。你必须小心把'extends Serializable'放在任何地方,因为这会造成内存泄漏。无论如何,我仍然不明白为什么在SBT控制台中运行Spark是不同的。我不认为Spark是SBT意识到的! – samthebest

+0

正如您所说,使用数据类别来确保数据清晰分离。对于使用对象的函数,通常具有比可序列化类更好的性能。如果将MaybeSerializable定义为对象,则可以通过另一种方式以高性能方式摆脱“不可序列化”的“任务不可序列化”异常。 – MiguelPeralvo