[英]Writing files to local system with Spark in Cluster mode
我知道这是一种使用Spark的奇怪方式,但我正在尝试使用Spark将数据帧保存到本地文件系统(而不是hdfs),即使我处于cluster mode
。 我知道我可以使用client mode
但我确实希望以cluster mode
运行,而不关心应用程序将作为驱动程序运行的节点(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-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
使用上面的代码java.io.IOException: Mkdirs failed to create file
。
我已经将df.coalesce(1)
部分更改为df.collect
并尝试使用普通Scala保存文件,但最终得到了Permission denied
。
我也尝试过:
root
用户spark-submit
chown
ed yarn:yarn
, yarn:hadoop
, spark:spark
chmod 777
给相关目录 但没有运气。
我假设这必须对clusters
, drivers and executors
尝试写入本地文件系统的user
drivers and executors
某些user
,但我自己一直坚持解决此问题。
我正在使用:
欢迎任何支持,并提前感谢。
我试过的一些文章:
chmod
没有帮助我 这是我得到的例外。
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)
我将回答我自己的问题,因为最终,没有一个答案似乎没有解决我的问题。 尽管如此,感谢所有答案并指出我可以检查的替代方案。
我认为@Ricardo最近提到了Spark应用程序的用户。 我用Process("whoami")
检查了whoami
,用户是yarn
。 问题可能是我试图输出到/home/foo/work/rhbase/r/input/input.csv
,虽然/home/foo/work/rhbase
由yarn:yarn
拥有yarn:yarn
, /home/foo
归foo:foo
。 我没有详细检查,但这可能是此permission
问题的原因。
当我使用Process("pwd")
在我的Spark应用程序中点击pwd
时,它输出/yarn/path/to/somewhere
。 所以我决定将我的文件输出到/yarn/input.csv
,尽管在cluster mode
它仍然成功。
我可能会得出结论,这只是一个简单的权限问题。 任何进一步的解决方案都会受到欢迎,但就目前而言,这就是我解决这个问题的方式。
使用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();
}
});
如果您以yarn-cluster mode
运行作业,驱动程序将在由YARN管理的任何机器中运行,因此如果saveAsTextFile
具有本地文件路径,则它将输出存储在运行驱动程序的任何机器中。
尝试将作业作为yarn-client mode
运行,以便驱动程序在客户端计算机中运行
检查您是否尝试使用Spark服务以外的用户运行/写入文件。 在这种情况下,您可以通过预设目录ACL来解决权限问题。 例:
setfacl -d -m group:spark:rwx /path/to/
(修改“spark”到试图写文件的用户组)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.