spark saveAsTextFile最后一个分区(几乎?)永远不会完成

时间:2015-08-04 09:50:18

标签: apache-spark

我有一个非常简单的字数统计程序,可以生成(长,双)计数:

val lines = sc.textFile(directory)

lines.repartition(600).mapPartitions{lineIterator => 
    // Generate iterator of (Long,Double) counts
}
.reduceByKey(new HashPartitioner(30), (v1, v2) => v1 + v2).saveAsTextFile(outDir, classOf[GzipCodec])

我的问题:30个分区中的最后一个永远不会被写入。

以下是一些细节:

  • 我的输入是5 GB gz压缩,我期望大约1B个唯一的长键。
  • 我在32核1.5TB机器上运行。输入和输出来自具有2TB空闲的本地磁盘。 Spark被指定使用所有ram并且愉快地这样做。此应用程序占用约0.5 TB。

我可以观察到以下内容:

  • 对于29个分区,reduce和repartition(因为HashPartitioner)大约需要2h。最后一个没有完成,甚至一天之后也没有完成。两到四个线程保持100%。
  • 日志中未显示错误或警告
  • Spark在/ tmp中占用大约100GB,与UI报告的shuffle写入一致。
  • 在用户界面中,我可以看到“随机阅读记录”的数量对于剩余的任务非常非常缓慢地增长。一天之后,距离所有已完成的任务显示的距离还有一个星期。

最后一个日志如下:

15/08/03 23:26:43 INFO SparkHadoopWriter: attempt_201508031748_0002_m_000020_748: Committed
15/08/03 23:26:43 INFO Executor: Finished task 20.0 in stage 2.0 (TID 748). 865 bytes result sent to driver
15/08/03 23:27:50 INFO FileOutputCommitter: Saved output of task 'attempt_201508031748_0002_m_000009_737' to file:/output-dir/_temporary/0/task_201508031748_0002_m_000009
15/08/03 23:27:50 INFO SparkHadoopWriter: attempt_201508031748_0002_m_000009_737: Committed
15/08/03 23:27:50 INFO Executor: Finished task 9.0 in stage 2.0 (TID 737). 865 bytes result sent to driver
15/08/04 02:44:54 INFO BlockManager: Removing broadcast 3
15/08/04 02:44:54 INFO BlockManager: Removing block broadcast_3_piece0
15/08/04 02:44:54 INFO MemoryStore: Block broadcast_3_piece0 of size 2009 dropped from memory (free 611091153849)
15/08/04 02:44:54 INFO BlockManagerMaster: Updated info of block broadcast_3_piece0
15/08/04 02:44:54 INFO BlockManager: Removing block broadcast_3
15/08/04 02:44:54 INFO MemoryStore: Block broadcast_3 of size 3336 dropped from memory (free 611091157185)
15/08/04 02:44:54 INFO BlockManager: Removing broadcast 4
15/08/04 02:44:54 INFO BlockManager: Removing block broadcast_4_piece0
15/08/04 02:44:54 INFO MemoryStore: Block broadcast_4_piece0 of size 2295 dropped from memory (free 611091159480)
15/08/04 02:44:54 INFO BlockManagerMaster: Updated info of block broadcast_4_piece0
15/08/04 02:44:54 INFO BlockManager: Removing block broadcast_4
15/08/04 02:44:54 INFO MemoryStore: Block broadcast_4 of size 4016 dropped from memory (free 611091163496)

想象一下,在两分钟的时间内,对于其他28个分区重复前五行。

我尝试了几件事:

  • Spark 1.3.0和1.4.0
  • nio而不是netty
  • flatMap而不是mapPartitions
  • 只有30个而不是600个输入分区

尽管如此,我从来没有从火花中获取最后1/30的数据。有没有人观察过类似的东西?这两个帖子herehere似乎描述了类似的问题但没有解决方案。

更新

永不完成的任务始终是reduceKey + writeToTextFile的第一项任务。我还删除了HashPartitioner,甚至尝试了一个包含400个核心和6000个分区的更大群集。只有5999成功完成,最后一次成功。

UI显示所有任务类似的内容 随机读取大小/记录:20.0 MB / 1954832 但是它显示的第一个(此刻) 随机读取大小/记录:150.1 MB / 711836

数字仍在增长......

1 个答案:

答案 0 :(得分:0)

可能是你的钥匙非常歪斜。根据它们的分布方式(或者如果您有一个空键或默认键),大量数据可能会转到单个执行程序,与在本地计算机上运行(加上分布式平台的开销)没有什么不同。它甚至可能导致该机器交换到磁盘,变得无法忍受地慢。

尝试使用aggregateByKey而不是reduceByKey,因为它会尝试获取跨执行程序分配的部分和,而不是将所有(可能很大的)键值对集合转移到单个执行程序。并且可以避免将输出分区的数量固定为30以防万一。

编辑:很难检测到问题"它只是没有完成"。你可以做的一件事是引入一个超时:

  val result = Await.result(future {
    // Your normal computation
  }, timeout)

这样,无论任务花费的时间太长,您都可以检测到并在现场收集一些指标。