在我的spark应用程序中,有一个object ResourceFactory
,其中包含一个用于提供资源客户端的akka ActorSystem
。因此,当我运行此spark应用程序时,每个工作节点都将创建一个ActorSystem
。问题是当spark应用程序完成其工作并关闭时。 ActorSystem
仍然在每个工作节点上保持活动状态,并阻止整个应用程序终止,它只是挂起。
有没有办法向SparkContext
注册一些监听器,以便在sc
关闭时,每个工作节点上的ActorSystem
都会收到通知自行关闭?
更新:
以下是简化的骨架:
有ResourceFactory
,object
,其中包含actor system
。它还提供了fetchData
方法。
object ResourceFactory{
val actorSystem = ActorSystem("resource-akka-system")
def fetchData(): SomeData = ...
}
然后,有一个user-defined RDD
类,在compute
方法中,它需要从ResourceFactory
获取数据。
class MyRDD extends RDD[SomeClass] {
override def compute(...) {
...
ResourceFactory.fetchData()
...
someIterator
}
}
因此,在每个节点上都会有一个名为“resource-akka-system”的ActorSystem
,并且在这些工作节点上分发的MyRDD
个实例可以从“resource-akka-system”获取数据
问题是,当SparkContext
关闭时,不需要那些“resource-akka-system”,但我不知道如何通知ResourceFactory
关闭SparkContext
关闭时的“resource-akka-system”。所以现在,“resouce-akka-system”在每个工作节点上保持活动状态,并阻止整个程序退出。
UPDATE2:
通过更多实验,我发现在本地模式下程序挂起,但在yarn-cluster
模式下,程序将成功退出。可能是因为yarn
会在sc
关闭时终止工作节点上的线程吗?
UPDATE3:
要检查每个节点是否包含ActorSystem
,我将代码更改如下(以下是真正的骨架,因为我添加了另一个类定义):
object ResourceFactory{
println("creating resource factory")
val actorSystem = ActorSystem("resource-akka-system")
def fetchData(): SomeData = ...
}
class MyRDD extends RDD[SomeClass] {
println("creating my rdd")
override def compute(...) {
new RDDIterator(...)
}
}
class RDDIterator(...) extends Iterator[SomeClass] {
println("creating rdd iterator")
...
lazy val reader = {
...
ResourceFactory.fetchData()
...
}
...
override next() = {
...
reader.xx()
}
}
添加println
后,我在yarn-cluster模式的spark上运行代码。我发现驱动程序上有以下打印件:
creating my rdd
creating resource factory
creating my rdd
...
在一些工人身上,我有以下印刷品:
creating rdd iterator
creating resource factory
有些工人没有打印任何东西(并且所有工作都没有分配任何任务)。
基于以上所述,我认为object
是在驱动程序中急切地初始化的,因为它会在驱动程序上打印creating resource factory
,即使没有任何东西引用它,并且object
已初始化工作人员懒惰,因为它在打印creating resource factory
后打印creating rdd iterator
,因为资源工厂被第一个创建的RDDIterator延迟引用。
我发现在我的用例中,MyRDD
类只在驱动程序中创建。
我不太确定object
对驱动程序和工作程序的初始化的懒惰,这是我的猜测,因为可能是程序的其他部分导致它看起来像那样。但我认为在必要时每个工作节点上都有一个actor系统应该是正确的。
答案 0 :(得分:2)
我认为没有办法进入每个Worker
生命周期。
此外,我对您的实施也有一些疑问:
如果你的object
包含val
,那是在函数运行中使用的,我的理解是这个val
被序列化并广播给worker。你能确认一下每个工人有一个ActorSystem吗?
如果你没有明确等待它的终止,那么演员系统通常会立即终止。您是否在system.awaitTermination
上调用system.whenTerminated
或阻止?
无论如何,还有另一种方法,如何关闭远程工作者的actor系统:
sc
所在的位置)向每个工作人员广播。简单来说,只需val
使用该地址。