Spark saveAsTextFile() 导致 Mkdirs 无法为一半目录创建

Posted

技术标签:

【中文标题】Spark saveAsTextFile() 导致 Mkdirs 无法为一半目录创建【英文标题】:Spark saveAsTextFile() results in Mkdirs failed to create for half of the directory 【发布时间】:2016-03-03 17:13:32 【问题描述】:

我目前在 tomcat 中运行 Java Spark 应用程序并收到以下异常:

Caused by: java.io.IOException: Mkdirs failed to create file:/opt/folder/tmp/file.json/_temporary/0/_temporary/attempt_201603031703_0001_m_000000_5

上线

text.saveAsTextFile("/opt/folder/tmp/file.json") //where text is a JavaRDD<String>

问题是 /opt/folder/tmp/ 已经存在并成功创建到 /opt/folder/tmp/file.json/_temporary/0/ 然后它遇到了看起来像剩下的权限问题路径 _temporary/attempt_201603031703_0001_m_000000_5 本身的一部分,但我将 tomcat 用户权限(chown -R tomcat:tomcat tmp/chmod -R 755 tmp/)授予 tmp/ 目录。有谁知道会发生什么?

谢谢

编辑@javadba:

[root@ip tmp]# ls -lrta 
total 12
drwxr-xr-x 4 tomcat tomcat 4096 Mar  3 16:44 ..
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 file.json
drwxrwxrwx 3 tomcat tomcat 4096 Mar  7 20:01 .

[root@ip tmp]# cd file.json/
[root@ip file.json]# ls -lrta 
total 12
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 _temporary
drwxrwxrwx 3 tomcat tomcat 4096 Mar  7 20:01 ..
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 .

[root@ip file.json]# cd _temporary/
[root@ip _temporary]# ls -lrta 
total 12
drwxr-xr-x 2 tomcat tomcat 4096 Mar  7 20:01 0
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 ..
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 .

[root@ip _temporary]# cd 0/
[root@ip 0]# ls -lrta 
total 8
drwxr-xr-x 3 tomcat tomcat 4096 Mar  7 20:01 ..
drwxr-xr-x 2 tomcat tomcat 4096 Mar  7 20:01 .

catalina.out 中的异常

Caused by: java.io.IOException: Mkdirs failed to create file:/opt/folder/tmp/file.json/_temporary/0/_temporary/attempt_201603072001_0001_m_000000_5
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:438)
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:424)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:906)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:799)
    at org.apache.hadoop.mapred.TextOutputFormat.getRecordWriter(TextOutputFormat.java:123)
    at org.apache.spark.SparkHadoopWriter.open(SparkHadoopWriter.scala:91)
    at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13.apply(PairRDDFunctions.scala:1193)
    at org.apache.spark.rdd.PairRDDFunctions$$anonfun$saveAsHadoopDataset$1$$anonfun$13.apply(PairRDDFunctions.scala:1185)
    at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:66)
    at org.apache.spark.scheduler.Task.run(Task.scala:89)
    at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:213)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    ... 1 more

【问题讨论】:

你能公布你是如何提交申请的吗?什么师傅?你有没有机会使用猜测? 【参考方案1】:

saveAsTextFile 真正由 Spark 执行器处理。根据您的 Spark 设置,Spark 执行程序可能以不同于您的 Spark 应用程序驱动程序的用户身份运行。我猜火花应用程序驱动程序为作业准备好目录,但是作为不同用户运行的执行程序无权在该目录中写入。

更改为 777 无济于事,因为权限不会被子目录继承,所以无论如何你都会得到 755。

尝试以运行 Spark 的同一用户身份运行 Spark 应用程序。

【讨论】:

最可能的响应。我刚刚将我的应用程序设置为使用 HDFS/S3 作为解决方法。没有遇到权限问题,如果我有机会我会回溯并确认这一点。 如何在同一个用户下运行 spark executors?【参考方案2】:

我建议暂时改成777。看看它在那个时候是否有效。本地文件系统上存在错误/问题 wrt 权限。如果这仍然不起作用,请告诉我们是否有任何变化或完全相同的结果。

【讨论】:

不幸的是,在 755 之前尝试过,结果是一样的。 请告诉我们ls -lrta /opt/folder/tmp/file.json/_temporary/0/_temporary的输出 抱歉耽搁了。添加了更新。就这样吧。它不能 mkdir 过去 0/ 它似乎【参考方案3】:

我也遇到了同样的问题,我的问题已经通过使用完整的 HDFS 路径解决了:

错误

原因:java.io.IOException:Mkdirs 未能创建文件:/QA/Gajendra/SparkAutomation/Source/_temporary/0/_temporary/attempt_20180616221100_0002_m_000000_0 (exists=false, cwd=file:/home/gajendra/LiClipse Workspace /SpakAggAutomation)

解决方案

使用带有hdfs://localhost:54310/<filePath>的完整HDFS路径

hdfs://localhost:54310/QA/Gajendra/SparkAutomation

【讨论】:

【参考方案4】:

会不会是 selinux/apparmor 在耍你?检查ls -Z 和系统日志。

【讨论】:

【参考方案5】:

所以,我遇到了同样的问题,我的设置没有 HDFS 并且 Spark 以独立模式运行。我无法使用本机 Spark 方法将 Spark 数据帧保存到 NFS 共享。该过程以本地用户身份运行,我尝试写入用户主文件夹。即使使用 777 创建子文件夹,我也无法写入该文件夹。

解决方法是使用toPandas() 转换数据帧,然后使用to_csv()。这很神奇。

【讨论】:

【参考方案6】:

我和你有同样的问题。

我也不想写入 hdfs,而是写入本地内存共享。

经过一番研究,我发现对于我的情况,原因是:有几个节点在执行,但是有些节点无法访问您要写入数据的目录。

所以解决办法是让目录对所有节点都可用,然后就可以了~

【讨论】:

你是怎么做到的【参考方案7】:

我们需要在本地模式下运行应用程序。

 val spark = SparkSession
      .builder()
      .config("spark.master", "local")
      .appName("applicationName")
      .getOrCreate()

【讨论】:

【参考方案8】:

这是一个棘手的问题,但很容易解决。必须配置 job.local.dir 变量指向工作目录。以下代码适用于编写 CSV 文件:

def xmlConvert(spark):
    etl_time = time.time()
    df = spark.read.format('com.databricks.spark.xml').options(rowTag='HistoricalTextData').load(
        '/home/zangetsu/proj/prometheus-core/demo/demo-1-iot-predictive-maintainance/dataset/train/')
    df = df.withColumn("TimeStamp", df["TimeStamp"].cast("timestamp")).groupBy("TimeStamp").pivot("TagName").sum(
        "TagValue").na.fill(0)
    df.repartition(1).write.csv(
        path="/home/zangetsu/proj/prometheus-core/demo/demo-1-iot-predictive-maintainance/result/",
        mode="overwrite",
        header=True,
        sep=",")
    print("Time taken to do xml transformation: --- %s seconds ---" % (time.time() - etl_time))


if __name__ == '__main__':
    spark = SparkSession \
        .builder \
        .appName('XML ETL') \
        .master("local[*]") \
        .config('job.local.dir', '/home/zangetsu/proj/prometheus-core/demo/demo-1-iot-predictive-maintainance') \
        .config('spark.driver.memory','64g') \
        .config('spark.debug.maxToStringFields','200') \
        .config('spark.jars.packages', 'com.databricks:spark-xml_2.11:0.5.0') \
        .getOrCreate()

    print('Session created')

    try:
        xmlConvert(spark)

    finally:
        spark.stop()

【讨论】:

以上是关于Spark saveAsTextFile() 导致 Mkdirs 无法为一半目录创建的主要内容,如果未能解决你的问题,请参考以下文章

Spark&Scala:saveAsTextFile()异常

Spark-saveAsTextFile 分区设置

Spark-saveAsTextFile 分区设置

Spark saveAsTextFile写入空文件 - _ $ folder $到S3

spark中saveAsTextFile如何最终生成一个文件

spark中saveAsTextFile如何最终生成一个文件