超时时退出缓慢的Spark映射,但到目前为止仍保留结果

时间:2018-07-06 09:52:54

标签: apache-spark

我正在通过Spark RDD进行映射,其功能非常昂贵(每行可能需要数十秒)。

该作业可能会花费太长时间,并且我需要中止该作业,以便为数据流中的其他作业让路。

但是,到目前为止计算出的结果对我仍然有用,所以我不想丢弃它们,尤其是因为它们可能已经花费了数小时来计算。

是否有办法在超时时提早退出转换,但保留到目前为止计算出的部分结果

1 个答案:

答案 0 :(得分:1)

通过从map切换到相关的转换,至少有几种方法可以实现:

mapPartitions

mapPartitions使我们可以访问每个分区上的迭代器,因此,如果超时到期,我们可以简单地假装其中没有任何项:

val data = sc.parallelize(1 to 100)

val timeout = 10000

val start = System.currentTimeMillis

data.repartition(10).mapPartitions { iter =>
  if (System.currentTimeMillis - start > timeout) Iterator.empty
  else iter.map(x => { Thread.sleep(500); x + 1 })
}.count

根据您的环境,您可能需要在此“火花壳”示例中调整超时,但是根据您运行转换的时间(相对于设置start),它应该产生不同数量的结果。

请注意,分区的数量必须明显大于执行器核心的总数,否则所有分区将立即启动,并且没有要跳过的内容。因此,对于此示例,我们在开始mapPartitions之前显式地对数据进行分区。您可能需要这样做,也可能不需要,这取决于数据的大小和预配置的内核数。

flatMap

更细粒度的方法是使用flatMap,它使我们可以通过返回Option的函数有条件地处理或跳过每一行(如果返回None超时已过期);

// setup as before
data.flatMap{ x => if (System.currentTimeMillis - start > timeout) None
                   else Some({Thread.sleep(500); x + 1}) }.count

此方法不需要分区,但是即使在超时后仍会扫描所有剩余分区(但不会对任何行执行昂贵的处理)。