web-dev-qa-db-fra.com

Écrire des fichiers sur un système local avec Spark en mode cluster

Je sais que c’est une façon étrange d’utiliser Spark, mais j’essaie de sauvegarder une base de données dans le système de fichiers local (et non en format hdfs) à l’aide de Spark, même si je suis dans cluster mode. Je sais que je peux utiliser client mode mais je fais veux exécuter cluster mode et ne me soucie pas du nœud (sur 3) sur lequel l'application va s'exécuter en tant que pilote . Le code ci-dessous est le pseudo code de ce que j'essaie de faire.

// 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")

Et voici comment je soumets la demande d'allumage.

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

Cela fonctionne bien si je suis dans local mode mais pas dans yarn-cluster mode.

Par exemple, Java.io.IOException: Mkdirs failed to create file apparaît avec le code ci-dessus.

J'ai changé la partie df.coalesce(1) en df.collect et j'ai essayé de sauvegarder un fichier en utilisant Scala mais cela s'est terminé par un Permission denied.

J'ai aussi essayé:

  • spark-submit avec root utilisateur
  • chowned yarn:yarn, yarn:hadoop, spark:spark
  • a donné chmod 777 à des répertoires apparentés

mais pas de chance.

Je suppose que cela doit faire quelque chose avec clusters, drivers and executors et le user qui essaie d'écrire dans le système de fichiers local, mais je suis plutôt coincé dans la résolution de ce problème par moi-même.

J'utilise:

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

Tout support est le bienvenu et merci d’avance.

Quelques articles que j'ai essayés:

  • "Les résultats de Spark saveAsTextFile () dans Mkdirs n'ont pas pu être créés pour la moitié du répertoire" -> J'ai essayé de changer d'utilisateur mais rien n'a changé
  • "Échec de l'enregistrement de RDD en tant que fichier texte sur le système de fichiers local" -> chmod ne m'a pas aidé

Edité (2016/11/25)

C'est l'exception que je reçois.

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)
12
tkrhgch

Je vais répondre à ma propre question car, finalement, aucune des réponses ne semblait résoudre mon problème. Néanmoins, merci pour toutes les réponses et m'indiquer des alternatives que je peux vérifier.

Je pense que @Ricardo était le plus proche des utilisateurs de l'application Spark. J'ai vérifié whoami avec Process("whoami") et l'utilisateur était yarn. Le problème était probablement que j'avais essayé de générer /home/foo/work/rhbase/r/input/input.csv et que /home/foo/work/rhbase appartenait à yarn:yarn, /home/foo appartenait à foo:foo. Je n'ai pas vérifié en détail, mais c'est peut-être la cause de ce problème permission.

Lorsque je clique sur pwd dans mon application Spark avec Process("pwd"), il génère /yarn/path/to/somewhere. J'ai donc décidé de sortir mon fichier dans /yarn/input.csv et le test a réussi malgré cluster mode.

Je peux probablement conclure qu'il s'agissait simplement d'un simple problème d'autorisation. Toute autre solution serait la bienvenue, mais pour l’instant, c’est ainsi que j’ai résolu cette question.

11
tkrhgch

Utilisez la méthode forEachPartition, puis pour chaque partition, récupérez un objet du système de fichiers et écrivez-y un enregistrement à la fois. Vous trouverez ci-dessous un exemple de code. Je vous écris sur 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();
        }
});
1
SanthoshPrasad

Si vous exécutez le travail en tant que yarn-cluster mode, le pilote sera exécuté sur l'un des ordinateurs gérés par YARN. Par conséquent, si saveAsTextFile a un chemin d'accès au fichier local, il stockera la sortie sur l'un des ordinateurs sur lequel le pilote est exécuté. 

Essayez d'exécuter le travail en tant que yarn-client mode afin que le pilote s'exécute sur l'ordinateur client.

1
Nirmal Ram

Vérifiez si vous essayez d'exécuter/d'écrire le fichier avec un utilisateur autre que le service Spark. Dans ce cas, vous pouvez résoudre le problème des autorisations en prédéfinissant les ACL du répertoire. Exemple:

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

(modifiez "spark" pour votre groupe d'utilisateurs essayant d'écrire le fichier)

0
Ricardo

Veuillez vous reporter à la documentation relative à spark pour comprendre l’utilisation de l’option --master dans spark-submit.

  • --master local est censé être utilisé lors de l'exécution locale.

  • --master yarn --deploy-mode cluster est censé être utilisé lors de l'exécution effective sur un cluster de fils.

Référez-vous ceci et ceci .

0
akaHuman