如何在火花停止时清理其他资源

时间:2016-04-13 10:00:14

标签: scala apache-spark akka

在我的spark应用程序中,有一个object ResourceFactory,其中包含一个用于提供资源客户端的akka​​ ActorSystem。因此,当我运行此spark应用程序时,每个工作节点都将创建一个ActorSystem。问题是当spark应用程序完成其工作并关闭时。 ActorSystem仍然在每个工作节点上保持活动状态,并阻止整个应用程序终止,它只是挂起。

有没有办法向SparkContext注册一些监听器,以便在sc关闭时,每个工作节点上的ActorSystem都会收到通知自行关闭?

更新:

以下是简化的骨架:

ResourceFactoryobject,其中包含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系统应该是正确的。

1 个答案:

答案 0 :(得分:2)

我认为没有办法进入每个Worker生命周期。

此外,我对您的实施也有一些疑问:

  1. 如果你的object包含val,那是在函数运行中使用的,我的理解是这个val被序列化并广播给worker。你能确认一下每个工人有一个ActorSystem吗?

  2. 如果你没有明确等待它的终止,那么演员系统通常会立即终止。您是否在system.awaitTermination上调用system.whenTerminated或阻止?



  3. 无论如何,还有另一种方法,如何关闭远程工作者的actor系统:

    1. 在akka群集的每个节点上创建ActorSystem。 Here are some docs如何以编程方式执行此操作。
    2. 有你"协调的地址"驱动程序节点上的Actor(您的sc所在的位置)向每个工作人员广播。简单来说,只需val使用该地址。
    3. 当您的每个工作人员启动您的akka​​系统时,使用"协调"注册此特定actor系统的Actor地址(向协调Actor发送相应的消息)。
    4. 协调演员跟踪所有已登记的"工人"演员
    5. 当您的计算完成并且您想要关闭每个工作人员的Akka系统时,请从驱动程序节点上的协调Actor向所有已注册的Actors发送消息。
    6. 当"关闭"关闭工作人员Akka系统收到消息。