为什么此Spark代码在本地模式下有效,但在集群模式下无效?

时间:2019-11-01 14:40:42

标签: scala apache-spark

所以,我有这样的事情。请注意,此处的baseTrait(一个特征)是可序列化的,因此thisClass(一个Object类)也应该是可序列化的。

object thisClass extends baseTrait {
  private var someVar = null 

  def someFunc: RDD[...] {
    ...
    // assigned some string value or an empty string value (not null anymore)
    someVar = ... 
    ...
    if (someVar != "")
      someRDD.filter(x => aFunc(x, someVar))
    else
      ...
  }

在集群模式下,当我调用someFunc函数(由于thisClass是一个Object类,这是一个静态方法)时,我得到一个空指针异常,我认为这与{{ 1}}未正确序列化。因为当我这样做时,它可以在群集模式下完美运行。

someVar

知道if (someVar != "") { val someVar_ = someVar someRDD.filter(x => aFunc(x, someVar_)) } 首先可序列化时原始代码出了什么问题吗?

我的猜测是,使用另一个类中的可序列化类的变量很好,但是如果您尝试在该类中使用它,则可能会遇到问题,因为在这种情况下,运行时将尝试序列化从中调用闭包的同一类。你觉得呢?

1 个答案:

答案 0 :(得分:3)

在这种情况下,您不会遇到序列化问题。

基本上,在集群模式下发生的事情是thisClass.someFunc从未真正在远程执行者的JVM中执行。在执行程序上,实例化thisClass,并为someVar分配了null。然后,在thisClass对象处于该状态时,spark框架直接在该执行程序的数据分区中可用的记录上执行lambda函数。

避免这种情况的一种方法是将对someVar的赋值移动到thisClass对象的主体中。这样做将在实例化对象时立即将值分配给someVar。请记住,该代码将在集群中的每个 执行程序上执行。

如果这不可能,则另一种选择是将RDD[T]映射到RDD[(T, String)],其中每条记录的字符串为someVar,然后您的过滤器可能类似于{ {1}}。此方法将使用更多的内存,因为您将拥有.filter(x => aFunc(x._1, x._2))值的许多副本。