使用Spark in Cluster模式将文件写入本地系统

时间:2016-11-24 12:10:36

标签: scala hadoop apache-spark

我知道这是一种使用Spark的奇怪方式,但我尝试使用Spark将数据帧保存到本地文件系统(而不是hdfs),即使我在cluster mode中也是如此。我知道我可以使用client mode但是我确实想要在cluster mode中运行,并且不关心应用程序将在哪个节点上运行作为司机。 下面的代码是我试图做的伪代码。

// create dataframe
val df = Seq(Foo("John", "Doe"), Foo("Jane", "Doe")).toDF()
// save it to the local file system using 'file://' because it defaults to hdfs://
df.coalesce(1).rdd.saveAsTextFile(s"file://path/to/file")

这就是我提交spark应用程序的方式。

spark-submit --class sample.HBaseSparkRSample --master yarn-cluster hbase-spark-r-sample-assembly-1.0.jar

如果我在local mode但在yarn-cluster mode中没有,那么这种方式可以正常工作。

例如,java.io.IOException: Mkdirs failed to create file出现在上面的代码中。

我已将df.coalesce(1)部分更改为df.collect,并尝试使用普通Scala保存文件,但结果却是Permission denied

我也尝试过:

  • spark-submitroot用户
  • chown ed yarn:yarnyarn:hadoopspark:spark
  • chmod 777提供给相关目录

但没有运气。

我假设这必须对clustersdrivers and executors以及user尝试写入本地文件系统但我很漂亮的事情做些什么我自己也很难解决这个问题。

我正在使用:

  • Spark:1.6.0-cdh5.8.2
  • Scala:2.10.5
  • Hadoop:2.6.0-cdh5.8.2

欢迎任何支持,并提前致谢。

我尝试过的一些文章:

  • " Spark saveAsTextFile()导致Mkdirs无法创建目录的一半" - >尝试改变用户但没有改变
  • "无法将RDD作为文本文件保存到本地文件系统" - > chmod没有帮助我

已编辑(2016/11/25)

这是我得到的例外。

java.io.IOException: Mkdirs failed to create file:/home/foo/work/rhbase/r/input/input.csv/_temporary/0/_temporary/attempt_201611242024_0000_m_000000_0 (exists=false, cwd=file:/yarn/nm/usercache/foo/appcache/application_1478068613528_0143/container_e87_1478068613528_0143_01_000001)
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:449)
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:435)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:920)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:813)
    at org.apache.hadoop.mapred.TextOutputFormat.getRecordWriter(TextOutputFormat.java:135)
    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:214)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
16/11/24 20:24:12 WARN scheduler.TaskSetManager: Lost task 0.0 in stage 0.0 (TID 0, localhost): java.io.IOException: Mkdirs failed to create file:/home/foo/work/rhbase/r/input/input.csv/_temporary/0/_temporary/attempt_201611242024_0000_m_000000_0 (exists=false, cwd=file:/yarn/nm/usercache/foo/appcache/application_1478068613528_0143/container_e87_1478068613528_0143_01_000001)
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:449)
    at org.apache.hadoop.fs.ChecksumFileSystem.create(ChecksumFileSystem.java:435)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:920)
    at org.apache.hadoop.fs.FileSystem.create(FileSystem.java:813)
    at org.apache.hadoop.mapred.TextOutputFormat.getRecordWriter(TextOutputFormat.java:135)
    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:214)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

5 个答案:

答案 0 :(得分:11)

我将回答我自己的问题,因为最终,没有一个答案似乎没有解决我的问题。尽管如此,感谢所有答案并指出我可以检查的替代方案。

我认为@Ricardo是提及Spark应用程序用户的最接近的人。我使用whoami检查了Process("whoami"),用户为yarn。问题可能是我尝试输出到/home/foo/work/rhbase/r/input/input.csv,虽然/home/foo/work/rhbaseyarn:yarn拥有,但/home/foofoo:foo所有。我没有详细检查,但这可能是导致permission问题的原因。

当我使用pwd点击我的Spark应用中的Process("pwd")时,会输出/yarn/path/to/somewhere。所以我决定将我的文件输出到/yarn/input.csv,尽管在cluster mode中已经成功了。

我可能会得出结论,这只是一个简单的权限问题。任何进一步的解决方案都会受到欢迎,但就目前而言,这就是我解决这个问题的方式。

答案 1 :(得分:1)

使用forEachPartition方法,然后为每个分区获取文件系统对象并逐个写入记录,下面是我在写hdfs的示例代码,而不是你也可以使用本地文件系统

Dataset<String> ds=....

ds.toJavaRdd.foreachPartition(new VoidFunction<Iterator<String>>() {
    @Override
    public void call(Iterator<String> iterator) throws Exception {

    final FileSystem hdfsFileSystem = FileSystem.get(URI.create(finalOutPathLocation), hadoopConf);

    final FSDataOutputStream fsDataOutPutStream = hdfsFileSystem.exists(finalOutPath)
            ? hdfsFileSystem.append(finalOutPath) : hdfsFileSystem.create(finalOutPath);


    long processedRecCtr = 0;
    long failedRecsCtr = 0;


    while (iterator.hasNext()) {

        try {
            fsDataOutPutStream.writeUTF(iterator.next);
        } catch (Exception e) {
            failedRecsCtr++;
        }
        if (processedRecCtr % 3000 == 0) {
            LOGGER.info("Flushing Records");
            fsDataOutPutStream.flush();
        }
    }

    fsDataOutPutStream.close();
        }
});

答案 2 :(得分:1)

如果您将作业运行为boost::none,则驱动程序将在YARN管理的任何计算机上运行,​​因此如果yarn-cluster mode具有本地文件路径,则它将存储输出任何运行驱动程序的机器。

尝试以saveAsTextFile运行作业,以便驱动程序在客户端计算机上运行

答案 3 :(得分:0)

请参阅spark文档,了解--masterspark-submit选项的使用情况。

  • --master local应该在本地运行时使用。

  • --master yarn --deploy-mode cluster应该在纱线群集上实际运行时使用。

参考thisthis

答案 4 :(得分:0)

检查您是否尝试使用Spark服务以外的用户运行/写入文件。 在这种情况下,您可以通过预设目录ACL来解决权限问题。例如:

setfacl -d -m group:spark:rwx /path/to/

(将“spark”修改为试图写入文件的用户组)