由于空间问题导致Spark作业失败

时间:2017-06-21 14:40:40

标签: hadoop apache-spark pyspark diskspace

我正在使用pyspark在Spark中编写批处理程序。 以下是输入文件及其大小

base-track.dat (3.9g)
base-attribute-link.dat (18g)
base-release.dat (543m)

这些文本文件每行有一条记录,每个字段用特殊字符(参考代码)分隔

我正在对属性链接执行一些过滤操作,并将它们分组并与其他表连接。

我通过spark-submit将这个程序提交给一个Hadoop集群,其中包含由Ambari管理的9个数据节点。 每个数据节点包含140 GB的RAM和3.5 TB的磁盘空间。

以下是我的pyspark代码

import sys

from pyspark import SparkContext
from pyspark.sql import SQLContext, Row

if __name__ == "__main__":
        sc = SparkContext(appName = "Tracks")
        sqlContext = SQLContext(sc)

        #Load base-track
        track = sc.textFile("base-track/input").map(lambda row: row.split(u'\u0001'))

        #Load base-attribute-link
        attlnk = sc.textFile("base-attribute-link/input").map(lambda row: row.split(u'\u0001'))

        #Load base-release
        release = sc.textFile("base-release/input").map(lambda row: row.split(u'\u0001'))

        attlnk = attlnk.filter(lambda row: row[2] == 'MA0000000162')

        attlnkg = attlnk.groupBy(lambda row: row[1])

        attlnkmax = attlnkg.map( lambda t: (t[0],max([v[4] for v in t[1]])) )

        alg = attlnkmax.map(lambda r: Row(al_objectid=r[0],al_value=r[1]))

        aldf = alg.toDF()

        track = track.map(lambda r:Row(t_tag = r[0], t_trackid= r[1], t_releaseid= r[2], t_songid = r[3], t_med= r[4], t_ph = r[5], t_tn = r[5], t_title= r[5], t_part= r[6], t_dur = r[7], t_pick = r[8], t_amgclid  = r[9], t_amgpopid = r[10], t_compid = r[11], t_muzid = r[12], t_perfid= r[13], t_albumid = r[14]))

        trackdf = track.toDF()

        release = release.map(lambda r:Row(r_tag = r[0], r_relid = r[1], r_albumid = r[2], r_mediafmtid = r[3], r_prodfmtid = r[4], r_reldate = r[5], r_prodcode = r[6], r_prodtypeid = r[7], r_label = r[8], r_relyear = r[9], r_ispurch = r[10], r_amgclassid = r[11], r_amgpopid = r[12], r_eanid = r[13], r_upcid = r[14]))

        releasedf = release.toDF()

        trackaldf = trackdf.join(aldf, trackdf['t_trackid'] == aldf['al_objectid'], 'left_outer')


        tracksdf = trackaldf.join(releasedf, trackaldf['t_releaseid'] == releasedf['r_relid'])

        tracksdf = tracksdf.select('t_trackid', 't_releaseid', 't_songid', 't_med', 't_ph', 't_tn', 't_title', 't_part', 't_dur', 't_pick', 't_amgclid', 't_amgpopid', 't_compid', 't_muzid', 'al_objectid', 't_perfid', 't_albumid', 'r_label')


        tracksdf.rdd.map(lambda x: u"\u0001".join(map(str, x))).coalesce(100).saveAsTextFile("tracks-out")

尝试执行此操作时遇到以下一些错误。

ERROR DiskBlockObjectWriter: Uncaught exception while reverting partial writes to file /tmp/blockmgr-d88c631e-cec3-4b83-8af6-a38b109b5e3b/0e/temp_shuffle_7dbda3ac-48b1-4c4a-89c7-64eb5d858d90
java.io.IOException: No space left on device
at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:326)
    at org.apache.spark.storage.TimeTrackingOutputStream.write(TimeTrackingOutputStream.java:58)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at org.xerial.snappy.SnappyOutputStream.flush(SnappyOutputStream.java:336)
    at org.apache.spark.io.SnappyOutputStreamWrapper.flush(CompressionCodec.scala:209)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:141)
    at java.io.DataOutputStream.flush(DataOutputStream.java:123)
    at org.apache.spark.sql.execution.UnsafeRowSerializerInstance$$anon$2.flush(UnsafeRowSerializer.scala:83)
    at org.apache.spark.storage.DiskBlockObjectWriter$$anonfun$revertPartialWritesAndClose$1.apply$mcV$sp(DiskBlockObjectWriter.scala:157)
    at org.apache.spark.storage.DiskBlockObjectWriter$$anonfun$revertPartialWritesAndClose$1.apply(DiskBlockObjectWriter.scala:154)
    at org.apache.spark.storage.DiskBlockObjectWriter$$anonfun$revertPartialWritesAndClose$1.apply(DiskBlockObjectWriter.scala:154)
    at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1239)
    at org.apache.spark.storage.DiskBlockObjectWriter.revertPartialWritesAndClose(DiskBlockObjectWriter.scala:161)
    at org.apache.spark.shuffle.sort.BypassMergeSortShuffleWriter.stop(BypassMergeSortShuffleWriter.java:232)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:79)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41)
    at org.apache.spark.scheduler.Task.run(Task.scala:89)
    at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:227)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

有关SO的问题,herehere与同一问题有关。

以下是我从上述两个问题中尝试过的内容。 我试图将spark.yarn.executor.memoryOverhead从384 MB增加到4GB。

SPARK_JAVA_OPTS+=" -Dspark.local.dir=/mnt/spark,/mnt2/spark -Dhadoop.tmp.dir=/mnt/ephemeral-hdfs"

export SPARK_JAVA_OPTS

第一个没有任何影响。如果我添加了java opts,我得到了/ mnt目录不存在的错误。

在多个论坛(包括databricks)上阅读了这个问题之后,得到了一些模糊的想法,这个工作正在尝试创建临时文件,作为每个群集节点上/ tmp的shuffle的一部分并耗尽空间。在每个群集节点上,我们为存在tmp目录的根(/)分区分配了100 GB。

我已经挣扎了一个多月,通过玩各种火花配置参数来执行此操作。作为调整的一部分,我将spark.driver和spark.executor内存增加到16g,后来增加到64g。还增加了火花纱执行器内存至4GB。不幸的是,这一切都无法解决太空问题。

任何有关如何进一步行动的指导都会有很大的帮助。

[Edit-1] 我刚刚检查了所有计算机上根目录的磁盘空间,我们集群中的9个节点中有7个节点已经为根目录分配了100 + GB,但在2个节点上只分配了10 GB,只剩下6 + GB。这可能导致磁盘空间问题,如果可以扩展根目录的大小,我将不得不与我们的IT团队核实。

[Edit-2] 我与IT团队一起在所有机器上将根分区大小扩展到100 + GB,但问题仍然存在,可能是100GB的/ tmp空间是这项工作还不够。我估计这份工作的输出大约是4.6GB。

2 个答案:

答案 0 :(得分:4)

鉴于您的错误的性质以及您在数十GB的数据上执行大型连接这一事实,其中spark worker会在中间数据写入时将其写入磁盘,100GB磁盘似乎不够。我建议为默认的worker_dir和local_dirs分配更多的磁盘,方法是将它们安装到更大的磁盘或配置更大的根磁盘。另请注意,如果spark未正常关闭,则此中间数据​​可能会延迟并占用工作节点上的大量空间。因此,您可能必须检查这些目录并删除任何陈旧的文件。如果您在AWS r3,c3或具有大型短暂SSD磁盘的类似实例类型上运行spark-standalone,我建议mounting这些磁盘说" mnt"和" mnt2"和configuring火花刮空间指向那些坐骑,而不是(通常)较小的根卷。 e.g:

SPARK_LOCAL_DIRS=/mnt
SPARK_WORKER_DIR=/mnt2

答案 1 :(得分:1)

我发现我没有将火花作业提交给群集,而是提交单个机器,因此磁盘空间问题。我总是以下面的方式提交我的脚本

spark-submit tracks.py

由于我希望我的脚本在Hadoop集群上执行并使用Yarn作为资源管理器,因此我将提交命令更改为以下内容,然后它运行正常。

spark-submit --master yarn --deploy-mode cluster tracks.py