Scala 在群集模式下使用Spark将文件写入本地系统

Scala 在群集模式下使用Spark将文件写入本地系统,scala,hadoop,apache-spark,Scala,Hadoop,Apache Spark,我知道这是使用Spark的一种奇怪的方式,但我正在尝试使用Spark将数据帧保存到本地文件系统(而不是hdfs),即使我处于集群模式。我知道我可以使用客户端模式,但是我确实想在集群模式下运行,并且不关心应用程序将作为驱动程序在哪个节点(共3个节点)上运行。 下面的代码是我尝试执行的伪代码 // create dataframe val df = Seq(Foo("John", "Doe"), Foo("Jane", "Doe")).toDF() // save it to the local f

我知道这是使用Spark的一种奇怪的方式,但我正在尝试使用Spark将数据帧保存到本地文件系统(而不是hdfs),即使我处于
集群模式
。我知道我可以使用
客户端模式
,但是我确实想在
集群模式下运行
,并且不关心应用程序将作为驱动程序在哪个节点(共3个节点)上运行。 下面的代码是我尝试执行的伪代码

// 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提交--class sample.hbaseparkrsample--master纱线簇hbase-spark-r-sample-assembly-1.0.jar

如果我处于
本地模式
,但未处于
纱线簇模式
,则此功能正常

例如,
java.io.IOException:Mkdirs无法创建文件
与上述代码一起出现

我已将
df.coalesce(1)
部分更改为
df.collect
,并尝试使用普通Scala保存一个文件,但最终导致
权限被拒绝

我也试过:

  • spark提交
    root
    用户
  • chown
    ed
    warn:warn
    warn:hadoop
    spark:spark
  • 向相关目录提供了
    chmod 777
但是没有运气

我假设这与
集群
驱动程序和执行程序
,以及试图写入本地文件系统但自己解决这个问题的
用户
有关

我正在使用:

  • 火花:1.6.0-cdh5.8.2
  • 斯卡拉: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)

请参阅spark文档以了解
spark submit
--master
选项的使用

  • ——本地运行时应该使用master local

  • --master warn--deploy mode cluster
    应该在纱线簇上实际运行时使用


请参阅并。

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

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

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

使用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();
        }
});
数据集ds=。。。。 foreachPartition(新的VoidFunction(){ @凌驾 公共void调用(迭代器迭代器)引发异常{ 最终文件系统hdfsFileSystem=FileSystem.get(URI.create(finalOutPathLocation),hadoopConf); 最终FSDataOutputStream FSDataOutputStream=hdfsFileSystem.exists(finalOutPath) ?hdfsFileSystem.append(finalOutPath):hdfsFileSystem.create(finalOutPath); 长处理的ECCTR=0; 长时间故障的牵引比=0; while(iterator.hasNext()){ 试一试{ fsDataOutPutStream.writeUTF(迭代器.next); }捕获(例外e){ failedRecsCtr++; } 如果(ProcessedRecCtrl%3000==0){ LOGGER.info(“冲洗记录”); fsDataOutPutStream.flush(); } } fsDataOutPutStream.close(); } });
如果您以
纱线簇模式运行作业,则驱动程序将在纱线管理的任何机器中运行,因此如果
saveAsTextFile
具有本地文件路径,则它将在驱动程序运行的任何机器中存储输出


尝试以
纱线客户端模式运行作业
以便驱动程序在客户端机器中运行

我将回答我自己的问题,因为最终,所有答案似乎都不能解决我的问题。尽管如此,还是要感谢所有的答案,并为我指出我可以检查的备选方案

我认为@Ricardo最接近于提到Spark应用程序的用户。我用
Process(“whoami”)
检查了
whoami
,用户是
warn
。问题可能是我试图输出到
/home/foo/work/rhbase/r/input/input.csv
,虽然
/home/foo/work/rhbase
属于
warn:warn
/home/foo
属于
foo:foo
。我尚未详细检查,但这可能是导致此
权限问题的原因

当我用
过程(“pwd”)
在Spark应用程序中点击
pwd
时,它输出
/warn/path/to/where
。所以我决定将我的文件输出到
/warn/input.csv
,尽管是在
集群模式下,它还是成功的


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

感谢您的快速回复。这是否意味着我无法使用参数?我的其他spark应用程序似乎在使用
纱线簇
参数的簇模式下正常工作。我将编辑我的问题,但我确实希望在群集模式下运行,但希望保存到本地文件系统,即使我不知道它将是哪个节点。谢谢您的建议。我知道这很奇怪,但我确实想在
纱线簇模式下运行。我有3个节点,我不关心驱动程序将位于哪个节点。但是无论哪个节点驱动程序正在运行,都只会在那里创建文件:)为什么不能存储数据