Ajouter des fichiers JAR à un travail Spark - Spark-submit

158

C'est vrai ... on en a beaucoup discuté.

Cependant, il y a beaucoup d'ambiguïté et certaines des réponses fournies ... y compris la duplication des références jar dans la configuration ou les options jars / executor / driver.

Les détails ambigus et / ou omis

Suite à l'ambiguïté, les détails peu clairs et / ou omis doivent être clarifiés pour chaque option:

  • Comment ClassPath est affecté
    • Chauffeur
    • Executor (pour les tâches en cours)
    • Tous les deux
    • pas du tout
  • Caractère de séparation: virgule, deux-points, point-virgule
  • Si les fichiers fournis sont automatiquement distribués
    • pour les tâches (à chaque exécuteur testamentaire)
    • pour le pilote distant (s'il est exécuté en mode cluster)
  • type d'URI accepté: fichier local, hdfs, http, etc.
  • S'il est copié dans un emplacement commun, où se trouve cet emplacement (hdfs, local?)

Les options sur lesquelles il affecte:

  1. --jars
  2. SparkContext.addJar(...) méthode
  3. SparkContext.addFile(...) méthode
  4. --conf spark.driver.extraClassPath=... ou --driver-class-path ...
  5. --conf spark.driver.extraLibraryPath=..., ou --driver-library-path ...
  6. --conf spark.executor.extraClassPath=...
  7. --conf spark.executor.extraLibraryPath=...
  8. à ne pas oublier, le dernier paramètre du spark-submit est également un fichier .jar.

Je sais où je peux trouver la documentation principale de Spark , et en particulier sur la façon de soumettre , les options disponibles, ainsi que le JavaDoc . Cependant, cela m'a laissé encore pas mal de trous, même si cela a répondu partiellement aussi.

J'espère que ce n'est pas si complexe et que quelqu'un pourra me donner une réponse claire et concise.

Si je devais deviner à partir de la documentation, il semble que --jars, et les méthodes SparkContext addJaret addFilesont celles qui distribueront automatiquement les fichiers, tandis que les autres options ne font que modifier le ClassPath.

Serait-il prudent de supposer que pour plus de simplicité, je peux ajouter des fichiers jar d'application supplémentaires en utilisant les 3 options principales en même temps:

spark-submit --jar additional1.jar,additional2.jar \
  --driver-library-path additional1.jar:additional2.jar \
  --conf spark.executor.extraLibraryPath=additional1.jar:additional2.jar \
  --class MyClass main-application.jar

J'ai trouvé un bel article sur une réponse à une autre publication . Cependant, rien de nouveau n'a été appris. L'affiche fait une bonne remarque sur la différence entre le pilote local (yarn-client) et le pilote distant (yarn-cluster). Il est absolument important de garder à l'esprit.

Yo-yo
la source
1
Sous quel gestionnaire de cluster exécutez-vous? Autonome / YARN / Mesos?
Yuval Itzchakov
Tout. J'entends cela comme une clarification de la documentation originale. J'utilise principalement un cluster autonome, une instance unique, un client de fil, un cluster de fils. D'autres utilisent peut-être Mesos. Il semble que vous ayez fait de bonnes recherches originales sur votre blog à ce sujet. J'ai fini par faire pratiquement la même chose que vous - en utilisant un shader pour créer un fichier Uber afin de simplifier mon processus de déploiement.
YoYo
1
Je publierai une réponse sur la façon dont nous déployons Spark Standalone, qui peut clarifier certaines choses.
Yuval Itzchakov
6
J'ai fait un effort pour répondre à toutes vos questions. J'espère que ça aide :)
Yuval Itzchakov
@Yuval Itzchakov, tout comme Yoyo l'a mentionné, j'utilise moi aussi un pot ombré pour regrouper toutes mes dépendances, par exemple les classes de cas, et d'autres fichiers que j'utilise. J'essaie de comprendre quand pourrais-je me retrouver dans une situation où j'ai besoin de plusieurs pots. Je veux dire que je peux toujours regrouper ces multiples pots dans 1 pot uber. Pourquoi ne puis-je pas continuer à vivre avec mes pots ombrés regroupant toutes mes dépendances?
Sheel Pancholi

Réponses:

177

ClassPath:

ClassPath est affecté en fonction de ce que vous fournissez. Il existe plusieurs façons de définir quelque chose sur le chemin de classe:

  • spark.driver.extraClassPathou c'est un alias --driver-class-pathpour définir des chemins de classe supplémentaires sur le nœud exécutant le pilote.
  • spark.executor.extraClassPath pour définir un chemin de classe supplémentaire sur les nœuds Worker.

Si vous voulez qu'un certain JAR soit effectué à la fois sur le maître et sur le travailleur, vous devez les spécifier séparément dans les DEUX indicateurs.

Caractère de séparation:

En suivant les mêmes règles que la JVM :

  • Linux: un deux-points :
    • par exemple: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar:/opt/prog/aws-java-sdk-1.10.50.jar"
  • Windows: un point-virgule ;
    • par exemple: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar;/opt/prog/aws-java-sdk-1.10.50.jar"

Distribution de fichiers:

Cela dépend du mode sous lequel vous exécutez votre travail:

  1. Mode client - Spark déclenche un serveur Netty HTTP qui distribue les fichiers au démarrage pour chacun des nœuds de travail. Vous pouvez le voir lorsque vous démarrez votre tâche Spark:

    16/05/08 17:29:12 INFO HttpFileServer: HTTP File server directory is /tmp/spark-48911afa-db63-4ffc-a298-015e8b96bc55/httpd-84ae312b-5863-4f4c-a1ea-537bfca2bc2b
    16/05/08 17:29:12 INFO HttpServer: Starting HTTP Server
    16/05/08 17:29:12 INFO Utils: Successfully started service 'HTTP file server' on port 58922.
    16/05/08 17:29:12 INFO SparkContext: Added JAR /opt/foo.jar at http://***:58922/jars/com.mycode.jar with timestamp 1462728552732
    16/05/08 17:29:12 INFO SparkContext: Added JAR /opt/aws-java-sdk-1.10.50.jar at http://***:58922/jars/aws-java-sdk-1.10.50.jar with timestamp 1462728552767
  2. Mode cluster - En mode cluster, Spark a sélectionné un nœud Worker leader sur lequel exécuter le processus Driver. Cela signifie que le travail ne s'exécute pas directement à partir du nœud maître. Ici, Spark ne définira pas de serveur HTTP. Vous devez rendre manuellement votre JARS disponible à tous les nœuds de travail via HDFS / S3 / Autres sources qui sont disponibles pour tous les nœuds.

URI acceptés pour les fichiers

Dans "Soumettre des demandes" , la documentation Spark explique bien les préfixes acceptés pour les fichiers:

Lorsque vous utilisez spark-submit, le fichier jar de l'application ainsi que tous les fichiers jar inclus avec l'option --jars seront automatiquement transférés vers le cluster. Spark utilise le schéma d'URL suivant pour autoriser différentes stratégies de diffusion de fichiers JAR:

  • file: - Les chemins absolus et le fichier: / Les URI sont servis par le serveur de fichiers HTTP du pilote, et chaque exécuteur extrait le fichier du serveur HTTP du pilote.
  • hdfs :, http :, https :, ftp: - ces fichiers déroulants et JAR de l'URI comme prévu
  • local: - un URI commençant par local: / devrait exister en tant que fichier local sur chaque nœud worker. Cela signifie qu'aucune E / S réseau ne sera encourue et fonctionne bien pour les fichiers / JAR volumineux qui sont poussés vers chaque travailleur ou partagés via NFS, GlusterFS, etc.

Notez que les fichiers JAR et les fichiers sont copiés dans le répertoire de travail de chaque SparkContext sur les nœuds exécuteurs.

Comme indiqué, les fichiers JAR sont copiés dans le répertoire de travail de chaque nœud Worker. Où est-ce exactement? C'est généralement sous /var/run/spark/work, vous les verrez comme ceci:

drwxr-xr-x    3 spark spark   4096 May 15 06:16 app-20160515061614-0027
drwxr-xr-x    3 spark spark   4096 May 15 07:04 app-20160515070442-0028
drwxr-xr-x    3 spark spark   4096 May 15 07:18 app-20160515071819-0029
drwxr-xr-x    3 spark spark   4096 May 15 07:38 app-20160515073852-0030
drwxr-xr-x    3 spark spark   4096 May 15 08:13 app-20160515081350-0031
drwxr-xr-x    3 spark spark   4096 May 18 17:20 app-20160518172020-0032
drwxr-xr-x    3 spark spark   4096 May 18 17:20 app-20160518172045-0033

Et quand vous regardez à l'intérieur, vous verrez tous les JAR que vous avez déployés:

[*@*]$ cd /var/run/spark/work/app-20160508173423-0014/1/
[*@*]$ ll
total 89988
-rwxr-xr-x 1 spark spark   801117 May  8 17:34 awscala_2.10-0.5.5.jar
-rwxr-xr-x 1 spark spark 29558264 May  8 17:34 aws-java-sdk-1.10.50.jar
-rwxr-xr-x 1 spark spark 59466931 May  8 17:34 com.mycode.code.jar
-rwxr-xr-x 1 spark spark  2308517 May  8 17:34 guava-19.0.jar
-rw-r--r-- 1 spark spark      457 May  8 17:34 stderr
-rw-r--r-- 1 spark spark        0 May  8 17:34 stdout

Options affectées:

La chose la plus importante à comprendre est la priorité . Si vous passez une propriété via le code, elle prévaudra sur toute option que vous spécifiez via spark-submit. Ceci est mentionné dans la documentation Spark:

Toutes les valeurs spécifiées comme indicateurs ou dans le fichier de propriétés seront transmises à l'application et fusionnées avec celles spécifiées via SparkConf. Les propriétés définies directement sur SparkConf ont la priorité la plus élevée , puis les indicateurs passés à spark-submit ou spark-shell, puis les options dans le fichier spark-defaults.conf

Assurez-vous donc de définir ces valeurs aux bons endroits, de sorte que vous ne serez pas surpris si l'une a priorité sur l'autre.

Permet d'analyser chaque option en question:

  • --jarsvs SparkContext.addJar: Ils sont identiques, un seul est défini via la soumission d'étincelle et un via le code. Choisissez celui qui vous convient le mieux. Une chose importante à noter est que l'utilisation de l'une de ces options n'ajoute pas le JAR au chemin de classe de votre pilote / exécuteur , vous devrez les ajouter explicitement en utilisant la extraClassPathconfiguration sur les deux.
  • SparkContext.addJarvs SparkContext.addFile: utilisez le premier lorsque vous avez une dépendance qui doit être utilisée avec votre code. Utilisez ce dernier lorsque vous souhaitez simplement transmettre un fichier arbitraire à vos nœuds de travail, ce qui n'est pas une dépendance d'exécution dans votre code.
  • --conf spark.driver.extraClassPath=...ou --driver-class-path: ce sont des alias, peu importe celui que vous choisissez
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... Idem que ci-dessus, alias.
  • --conf spark.executor.extraClassPath=...: Utilisez cette option lorsque vous avez une dépendance qui ne peut pas être incluse dans un JAR uber (par exemple, car il y a des conflits de compilation entre les versions de bibliothèque) et que vous devez charger au moment de l'exécution.
  • --conf spark.executor.extraLibraryPath=...Ceci est passé comme java.library.pathoption pour la JVM. Utilisez cette option lorsque vous avez besoin d'un chemin de bibliothèque visible par la JVM.

Serait-il prudent de supposer que pour plus de simplicité, je peux ajouter des fichiers jar d'application supplémentaires en utilisant les 3 options principales en même temps:

Vous pouvez supposer cela en toute sécurité uniquement pour le mode client et non pour le mode cluster. Comme je l'ai déjà dit. De plus, l'exemple que vous avez donné contient des arguments redondants. Par exemple, passer des fichiers JAR à --driver-library-pathest inutile, vous devez les transmettre à extraClassPathsi vous voulez qu'ils soient sur votre chemin de classe. En fin de compte, ce que vous voulez faire lorsque vous déployez des JAR externes sur le pilote et le worker est:

spark-submit --jars additional1.jar,additional2.jar \
  --driver-class-path additional1.jar:additional2.jar \
  --conf spark.executor.extraClassPath=additional1.jar:additional2.jar \
  --class MyClass main-application.jar
Yuval Itzchakov
la source
4
Réponse excellente et complète. Je vous remercie. Pourriez-vous également en dire plus sur les meilleures pratiques de déploiement avec uber JAR par rapport aux dépendances en dehors de JAR (bibliothèques dans un dossier externe et répertoriées dans un MANIFEST.MFfichier)?
jsosnowski
2
@jsosnowski Habituellement, je m'en remets uniquement à l'utilisation de jars externes lorsqu'il y a des conflits très complexes à résoudre avec mon uber JAR. Je me débrouille généralement simplement en utilisant les SBT assemblyMergeStrategyet en sélectionnant les classes dont j'ai besoin s'il y a des conflits. Je recommande généralement la même chose.
Yuval Itzchakov
9
@ yuval-itzchakov Merci pour la bonne réponse, très utile. Je voudrais souligner un point pour aider les autres qui ont peut-être commis la même erreur que moi. L'argument --jars transporte uniquement les fichiers JAR vers chaque machine du cluster. Il ne dit PAS à Spark de les utiliser dans la recherche de chemin de classe. Le --driver-class-path (ou des arguments similaires ou des paramètres de configuration) sont également requis. Au départ, je pensais que c'était des façons alternatives de faire la même chose.
Tim Ryan
1
@TimRyan Certainement. Si vous regardez la dernière partie de la réponse, je passe les fichiers JAR à la fois au --jarsdrapeau et au chemin de classe du pilote / exécuteur.
Yuval Itzchakov
1
Finalement , j'ai trouvé comment injecter des variables d'environnement dans zeppelin-env.shet ajouté --jarsà SPARK_SUBMIT_OPTIONS. Ça a marché. Le format URI que j'utilise est --jars=local:///mnt/dir/file.jar.
Mike
4

Une autre approche spark 2.1.0consiste à utiliser --conf spark.driver.userClassPathFirst=truependant Spark-submit qui change la priorité de la charge de dépendance, et donc le comportement du Spark-Job, en donnant la priorité aux jars que l'utilisateur ajoute au class-path avec l' --jarsoption.

Stanislav
la source
2
Vous devrez faire attention à cela - car il est possible de briser l'étincelle en le faisant. Cela devrait être une solution de dernière option. Cela pourrait potentiellement interférer avec l'interfaçage de la couche avec le fil lors de l'utilisation en mode fil-client, bien que je ne sois pas sûr.
YoYo
Merci pour la mise en garde. Existe-t-il un moyen de donner la priorité à un seul pot, qui existe certainement dans le serveur dans une version plus ancienne mais que vous ne pouvez pas remplacer physiquement et vous savez que vous ne voulez pas utiliser?
Stanislav
1
Je suppose que dans ce cas, vous pourriez essayer exactement comme vous l'avez suggéré. Je n'ai pas dit que c'était un non absolu. Notez également que l'option est marquée comme «expérimentale» - un avertissement à prendre en compte! Il n'existe aucun moyen sûr de donner la priorité à une version d'une bibliothèque par rapport à une autre. Dans certaines implémentations, ce problème est résolu en déplaçant l'une des bibliothèques dans un espace de noms différent, afin que vous puissiez utiliser les deux versions en même temps.
YoYo
1

Les autres options Spark configurables relatives aux fichiers jars et classpath, en cas de yarnmode de déploiement, sont les suivantes
.

spark.yarn.jars

Liste des bibliothèques contenant du code Spark à distribuer aux conteneurs YARN. Par défaut, Spark sur YARN utilisera les jars Spark installés localement, mais les jars Spark peuvent également être dans un emplacement lisible par le monde sur HDFS. Cela permet à YARN de le mettre en cache sur les nœuds afin qu'il n'ait pas besoin d'être distribué à chaque exécution d'une application. Pour pointer vers des fichiers JAR sur HDFS, par exemple, définissez cette configuration sur hdfs: /// some / path. Les globes sont autorisés.

spark.yarn.archive

Une archive contenant les fichiers JAR Spark nécessaires pour la distribution dans le cache YARN. Si elle est définie, cette configuration remplace spark.yarn.jars et l'archive est utilisée dans tous les conteneurs de l'application. L'archive doit contenir des fichiers jar dans son répertoire racine. Comme avec l'option précédente, l'archive peut également être hébergée sur HDFS pour accélérer la distribution des fichiers.

Les utilisateurs peuvent configurer ce paramètre pour spécifier leurs fichiers JAR, qui inturn sont inclus dans le chemin de classe du pilote Spark.

Homme sombre
la source
1

Lorsque vous utilisez spark-submit avec --master yarn-cluster, le fichier jar de l'application ainsi que tous les fichiers jar inclus avec l'option --jars seront automatiquement transférés vers le cluster. Les URL fournies après --jars doivent être séparées par des virgules. Cette liste est incluse dans les chemins de classe du pilote et de l'exécuteur

Exemple :

spark-submit --master yarn-cluster --jars ../lib/misc.jar, ../lib/test.jar --class MainClass MainApp.jar

https://spark.apache.org/docs/latest/submitting-applications.html

Shiva Garg
la source
0

Il y a une restriction sur l'utilisation --jars: si vous souhaitez spécifier un répertoire pour l'emplacement du jar/xmlfichier, cela n'autorise pas les extensions de répertoire. Cela signifie que vous devez spécifier un chemin absolu pour chaque fichier jar.

Si vous spécifiez --driver-class-pathet que vous exécutez en mode cluster de fils, la classe de pilote n'est pas mise à jour. Nous pouvons vérifier si le chemin de classe est mis à jour ou non sous Spark ui ou Spark History Server sous l'onglet environnement.

L'option qui a fonctionné pour moi pour passer des jars contenant des extensions de répertoire et qui fonctionnait en mode cluster de fils était une --confoption. Il est préférable de transmettre les chemins de classe du pilote et de l'exécuteur en tant que --conf, ce qui les ajoute à l'objet de session Spark lui-même et ces chemins sont reflétés sur la configuration Spark. Mais assurez-vous de placer les fichiers JAR sur le même chemin à travers le cluster.

spark-submit \
  --master yarn \
  --queue spark_queue \
  --deploy-mode cluster    \
  --num-executors 12 \
  --executor-memory 4g \
  --driver-memory 8g \
  --executor-cores 4 \
  --conf spark.ui.enabled=False \
  --conf spark.driver.extraClassPath=/usr/hdp/current/hbase-master/lib/hbase-server.jar:/usr/hdp/current/hbase-master/lib/hbase-common.jar:/usr/hdp/current/hbase-master/lib/hbase-client.jar:/usr/hdp/current/hbase-master/lib/zookeeper.jar:/usr/hdp/current/hbase-master/lib/hbase-protocol.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/scopt_2.11-3.3.0.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/spark-examples_2.10-1.1.0.jar:/etc/hbase/conf \
  --conf spark.hadoop.mapred.output.dir=/tmp \
  --conf spark.executor.extraClassPath=/usr/hdp/current/hbase-master/lib/hbase-server.jar:/usr/hdp/current/hbase-master/lib/hbase-common.jar:/usr/hdp/current/hbase-master/lib/hbase-client.jar:/usr/hdp/current/hbase-master/lib/zookeeper.jar:/usr/hdp/current/hbase-master/lib/hbase-protocol.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/scopt_2.11-3.3.0.jar:/usr/hdp/current/spark2-thriftserver/examples/jars/spark-examples_2.10-1.1.0.jar:/etc/hbase/conf \
  --conf spark.hadoop.mapreduce.output.fileoutputformat.outputdir=/tmp
Tanveer
la source
Bonne année!
YoYo
Happy New Year YoYo
Tanveer
0

Alors que nous soumettons des travaux Spark à l'aide de l'utilitaire spark-submit, il existe une option --jars. En utilisant cette option, nous pouvons passer un fichier jar pour déclencher des applications.

bala
la source
Le fait qu'il y ait cette —jaroption a été mentionné par l'affiche originale, plus discuté de manière beaucoup plus détaillée par plus d'une réponse. Il ne semble pas que vous fournissiez quelque chose de nouveau?
YoYo