执行者上的Spark对象(单例)序列化

执行者上的Spark对象(单例)序列化

问题描述:

我不确定我想实现的是否可能。我所知道的是,我正从一个执行器访问单例对象,以确保它的构造器在每个执行器上只被调用一次。这种模式已经在我的代码库中被证明和按照预期用于类似的用例。执行者上的Spark对象(单例)序列化

但是,我想知道的是,如果我可以在驱动程序初始化之后运送对象。在这种情况下, 访问ExecutorAccessedObject.y时,理想情况下它不会调用println,而是返回值。这是一个高度简化的版本,实际上,我想打电话给驱动程序上的某个外部系统,因此在执行程序*问时,它不会重新调用该外部系统。我确信@transient lazy val x在执行者上被重新初始化,因为这将持有无法序列化的连接池。

object ExecutorAccessedObject extends Serializable { 
    @transient lazy val x: Int = { 
    println("Ok with initialzing this on the executor. I.E. database connection pool") 
    1 
    } 

    val y: Int = { 
    // call some external system to return a value. 
    // I do not want to call the external system from the executor 
    println(
     """ 
     |Idealy, this would not be printed on the executor. 
     |return value 1 without re initializing 
     """) 
    1 
    } 
    println("The constructor will be initialized Once on each executor") 
} 


someRdd.mapPartitions { part => 
    ExecutorAccessedObject 
    ExecutorAccessedObject.x // first time accessed should re-evaluate 
    ExecutorAccessedObject.y // idealy, never re-evaluate and return 1 
    part 
} 

我试图用广播变量解决这个问题,但我不确定如何访问单例对象内的广播变量。

我想知道的是,如果我可以在驱动程序初始化之后装运对象。

你不能。作为单身人士,我们绝不会将其运送给执行人。在本地初始化时,只要第一次访问对象。

如果调用的结果是可序列化的,只需将其作为参数传递给ExecutorAccessedObject(隐式或显式地)或使ExecutorAccessedObject可变(并添加所需的同步)即可。

+0

谢谢你的回答。当你说明确地将参数传递给对象时,你的意思是使它成为一个带有参数的类? –

+0

我宁愿考虑参数化方法调用。使用类而不是对象应该也可以。 – user8925690