Hinzufügen von Gläsern zu einem Spark-Job - Spark-Submit

158

Stimmt ... es wurde ziemlich viel diskutiert.

Es gibt jedoch viele Unklarheiten und einige der Antworten ... einschließlich des Duplizierens von JAR-Referenzen in der JAR- / Executor- / Treiberkonfiguration oder in den Optionen.

Die mehrdeutigen und / oder ausgelassenen Details

Nach Unklarheiten sollten für jede Option unklare und / oder ausgelassene Details geklärt werden:

  • Wie ClassPath betroffen ist
    • Treiber
    • Executor (für laufende Aufgaben)
    • Beide
    • keineswegs
  • Trennzeichen: Komma, Doppelpunkt, Semikolon
  • Wenn angegeben, werden Dateien automatisch verteilt
    • für die Aufgaben (an jeden Testamentsvollstrecker)
    • für den Remote-Treiber (wenn im Cluster-Modus ausgeführt)
  • Art der akzeptierten URI: lokale Datei, HDFS, http usw.
  • Wenn an einen gemeinsamen Speicherort kopiert , wo befindet sich dieser Speicherort (hdfs, local?)

Die Optionen, auf die es sich auswirkt:

  1. --jars
  2. SparkContext.addJar(...) Methode
  3. SparkContext.addFile(...) Methode
  4. --conf spark.driver.extraClassPath=... oder --driver-class-path ...
  5. --conf spark.driver.extraLibraryPath=..., oder --driver-library-path ...
  6. --conf spark.executor.extraClassPath=...
  7. --conf spark.executor.extraLibraryPath=...
  8. Nicht zu vergessen, der letzte Parameter des Spark-Submit ist ebenfalls eine JAR-Datei.

Mir ist bekannt, wo ich die Hauptdokumentation zu Spark finden kann , und insbesondere, wie ich sie einreichen soll , welche Optionen verfügbar sind und auch JavaDoc . Das ließ mir jedoch noch einige Löcher, obwohl es teilweise auch antwortete.

Ich hoffe, dass es nicht so komplex ist und dass mir jemand eine klare und präzise Antwort geben kann.

Wenn ich aus der Dokumentation raten würde, scheint es so --jars, und die Methoden SparkContext addJarund addFilesind diejenigen, die automatisch Dateien verteilen, während die anderen Optionen lediglich den ClassPath ändern.

Wäre es sicher anzunehmen, dass ich der Einfachheit halber zusätzliche Anwendungs-JAR-Dateien hinzufügen kann, indem ich gleichzeitig die drei Hauptoptionen verwende:

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

Fand einen schönen Artikel über eine Antwort auf einen anderen Beitrag . Allerdings nichts Neues gelernt. Das Poster macht eine gute Bemerkung zum Unterschied zwischen lokalem Treiber (Garn-Client) und entferntem Treiber (Garn-Cluster). Auf jeden Fall wichtig zu beachten.

YoYo
quelle
1
Unter welchem ​​Cluster Manager laufen Sie? Standalone / YARN / Mesos?
Yuval Itzchakov
Irgendein. Ich beabsichtige dies als Klarstellung zur Originaldokumentation. Ich verwende hauptsächlich Standalone-Cluster, Einzelinstanz, Garn-Client, Garn-Cluster. Andere verwenden möglicherweise Mesos. Es scheint, dass Sie in Ihrem Blog einige gute Originalrecherchen dazu durchgeführt haben. Am Ende habe ich fast das Gleiche getan wie Sie - mit einem Shader ein Uber-JAR erstellt, um meinen Bereitstellungsprozess zu vereinfachen.
YoYo
1
Ich werde eine Antwort bezüglich der Bereitstellung von Spark Standalone veröffentlichen, die einige Dinge klären kann.
Yuval Itzchakov
6
Ich habe mich bemüht, alle Ihre Fragen zu beantworten. Hoffe es hilft :)
Yuval Itzchakov
@ Yuval Itzchakov, genau wie Yoyo es erwähnt hat, verwende auch ich ein schattiertes Glas, um alle meine Abhängigkeiten zu bündeln, z. B. Fallklassen und andere Gläser, die ich möglicherweise verwende. Ich versuche zu verstehen, wann ich in eine Situation geraten würde, in der ich mehrere Gläser benötige. Ich meine, ich kann diese mehreren Gläser immer in einem übergroßen Glas bündeln. Warum kann ich nicht weiter mit meinen schattierten Gläsern leben, die alle meine Abhängigkeiten bündeln?
Sheel Pancholi

Antworten:

176

ClassPath:

ClassPath ist abhängig von Ihrer Bereitstellung betroffen. Es gibt verschiedene Möglichkeiten, etwas auf den Klassenpfad zu setzen:

  • spark.driver.extraClassPathoder es ist ein Alias --driver-class-path, zusätzliche Klassenpfade auf dem Knoten festzulegen, auf dem der Treiber ausgeführt wird.
  • spark.executor.extraClassPath um einen zusätzlichen Klassenpfad auf den Worker-Knoten festzulegen.

Wenn eine bestimmte JAR sowohl für den Master als auch für den Worker ausgeführt werden soll, müssen Sie diese in BEIDEN Flags separat angeben.

Trennungszeichen:

Befolgen Sie die gleichen Regeln wie bei der JVM :

  • Linux: Ein Doppelpunkt :
    • z.B: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar:/opt/prog/aws-java-sdk-1.10.50.jar"
  • Windows: Ein Semikolon ;
    • z.B: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar;/opt/prog/aws-java-sdk-1.10.50.jar"

Dateiverteilung:

Dies hängt vom Modus ab, in dem Sie Ihren Job ausführen:

  1. Client-Modus - Spark startet einen Netty-HTTP-Server, der die Dateien beim Start für jeden der Worker-Knoten verteilt. Sie können dies sehen, wenn Sie Ihren Spark-Job starten:

    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. Cluster-Modus - Im Cluster-Modus hat spark einen führenden Worker-Knoten ausgewählt, auf dem der Treiberprozess ausgeführt werden soll. Dies bedeutet, dass der Job nicht direkt vom Master-Knoten ausgeführt wird. Hier setzt Spark keinen HTTP-Server. Sie müssen Ihre JARS manuell für alle Worker-Knoten über HDFS / S3 / andere Quellen verfügbar machen, die allen Knoten zur Verfügung stehen.

Akzeptierte URIs für Dateien

In "Einreichen von Anträgen" werden in der Spark-Dokumentation die akzeptierten Präfixe für Dateien gut erläutert:

Bei Verwendung von spark-submit wird das Anwendungsglas zusammen mit allen in der Option --jars enthaltenen Gläsern automatisch in den Cluster übertragen. Spark verwendet das folgende URL-Schema, um verschiedene Strategien für die Verbreitung von Gläsern zu ermöglichen:

  • Datei: - Absolute Pfade und Datei: / URIs werden vom HTTP-Dateiserver des Treibers bereitgestellt, und jeder Executor ruft die Datei vom HTTP-Server des Treibers ab.
  • hdfs:, http:, https:, ftp: - Diese Pulldown-Dateien und JARs werden erwartungsgemäß vom URI abgerufen
  • local: - Es wird erwartet, dass ein URI, der mit local: / beginnt, als lokale Datei auf jedem Arbeitsknoten vorhanden ist. Dies bedeutet, dass keine Netzwerk-E / A anfallen und gut für große Dateien / JARs geeignet sind, die an jeden Worker übertragen oder über NFS, GlusterFS usw. freigegeben werden.

Beachten Sie, dass JARs und Dateien für jeden SparkContext auf den Executor-Knoten in das Arbeitsverzeichnis kopiert werden.

Wie bereits erwähnt, werden JARs für jeden Worker-Knoten in das Arbeitsverzeichnis kopiert . Wo genau ist das? Es ist normalerweise unter /var/run/spark/work, Sie werden sie so sehen:

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

Und wenn Sie nach innen schauen, sehen Sie alle JARs, die Sie bereitgestellt haben:

[*@*]$ 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

Betroffene Optionen:

Das Wichtigste, was zu verstehen ist, ist die Priorität . Wenn Sie eine Eigenschaft per Code übergeben, hat sie Vorrang vor allen Optionen, die Sie über angeben spark-submit. Dies wird in der Spark-Dokumentation erwähnt:

Alle als Flags oder in der Eigenschaftendatei angegebenen Werte werden an die Anwendung übergeben und mit den über SparkConf angegebenen Werten zusammengeführt. Direkt in der SparkConf festgelegte Eigenschaften haben höchste Priorität , dann werden Flags an spark- submit oder spark-shell übergeben und anschließend Optionen in der Datei spark-defaults.conf

Stellen Sie also sicher, dass Sie diese Werte an den richtigen Stellen einstellen, damit Sie nicht überrascht sind, wenn einer Vorrang vor dem anderen hat.

Analysieren wir jede fragliche Option:

  • --jarsvs SparkContext.addJar: Diese sind identisch, nur eine wird durch Spark Submit und eine per Code gesetzt. Wählen Sie diejenige, die besser zu Ihnen passt. Eine wichtige Sache, die Sie beachten sollten, ist, dass bei Verwendung einer dieser Optionen die JAR nicht zu Ihrem Treiber- / Executor-Klassenpfad hinzugefügt wird. Sie müssen sie explizit mithilfe der extraClassPathKonfiguration für beide hinzufügen .
  • SparkContext.addJarvs SparkContext.addFile: Verwenden Sie erstere, wenn Sie eine Abhängigkeit haben , die mit Ihrem Code verwendet werden muss. Verwenden Sie Letzteres, wenn Sie einfach eine beliebige Datei an Ihre Worker-Knoten weitergeben möchten, was keine Laufzeitabhängigkeit in Ihrem Code darstellt.
  • --conf spark.driver.extraClassPath=...oder --driver-class-path: Dies sind Aliase, egal welchen Sie wählen
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... Wie oben, Aliase.
  • --conf spark.executor.extraClassPath=...: Verwenden Sie diese Option, wenn Sie eine Abhängigkeit haben, die nicht in eine über JAR aufgenommen werden kann (z. B. weil zwischen Bibliotheksversionen Konflikte bei der Kompilierung bestehen) und die Sie zur Laufzeit laden müssen.
  • --conf spark.executor.extraLibraryPath=...Dies wird als java.library.pathOption für die JVM übergeben. Verwenden Sie diese Option, wenn Sie einen Bibliothekspfad benötigen, der für die JVM sichtbar ist.

Wäre es sicher anzunehmen, dass ich der Einfachheit halber zusätzliche Anwendungs-JAR-Dateien hinzufügen kann, indem ich gleichzeitig die drei Hauptoptionen verwende:

Sie können dies sicher nur für den Client-Modus und nicht für den Cluster-Modus annehmen. Wie ich schon sagte. Das von Ihnen angegebene Beispiel enthält außerdem einige redundante Argumente. Das Übergeben von JARs an --driver-library-pathist beispielsweise nutzlos. Sie müssen sie an übergeben, extraClassPathwenn Sie möchten, dass sie sich auf Ihrem Klassenpfad befinden. Letztendlich möchten Sie Folgendes tun, wenn Sie externe JARs sowohl auf dem Treiber als auch auf dem Worker bereitstellen:

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
quelle
4
Tolle und umfassende Antwort. Danke dir. Könnten Sie auch mit mehr über die besten Praktiken bei der Bereitstellung sagen uber JAR vs. Abhängigkeiten außerhalb JAR (Libs in externen Ordner und aufgeführt in MANIFEST.MFDatei)?
Jsosnowski
2
@jsosnowski Normalerweise verzichte ich nur dann auf die Verwendung externer Gläser, wenn es Konflikte gibt, deren Lösung mit meinem über JAR sehr komplex ist. Normalerweise komme ich einfach damit zurecht, SBTs zu verwenden assemblyMergeStrategyund die Klassen auszuwählen, die ich bei Konflikten benötige. Ich würde im Allgemeinen das gleiche empfehlen.
Yuval Itzchakov
9
@ yuval-itzchakov Danke für die tolle Antwort, sehr hilfreich. Ein Punkt möchte ich hervorheben, um anderen zu helfen, die möglicherweise den gleichen Fehler gemacht haben wie ich. Das Argument --jars transportiert nur die Jars zu jedem Computer im Cluster. Es weist spark NICHT an, sie bei der Suche nach Klassenpfaden zu verwenden. Der --driver-class-path (oder ähnliche Argumente oder Konfigurationsparameter) sind ebenfalls erforderlich. Anfangs dachte ich, sie wären alternative Wege, um dasselbe zu tun.
Tim Ryan
1
@ TimRyan Auf jeden Fall. Wenn Sie sich den letzten Teil der Antwort ansehen, übergebe ich Gläser sowohl an das --jarsFlag als auch an den Pfad der Treiber- / Executor-Klasse.
Yuval Itzchakov
1
Schließlich fand ich , wie zu injizieren Umgebungsvariablen in zeppelin-env.shund hinzugefügt --jarszu SPARK_SUBMIT_OPTIONS. Das hat funktioniert. Das von mir verwendete URI-Format ist --jars=local:///mnt/dir/file.jar.
Mike
4

Ein anderer Ansatz spark 2.1.0besteht darin, --conf spark.driver.userClassPathFirst=truewährend der Funkenübermittlung zu verwenden , wodurch die Priorität der Abhängigkeitslast und damit das Verhalten des Funkenauftrags geändert wird, indem den Gläsern Priorität eingeräumt wird, die der Benutzer mit der --jarsOption zum Klassenpfad hinzufügt .

Stanislav
quelle
2
Damit müssen Sie vorsichtig sein - da es möglich ist, den Funken zu brechen. Dies sollte eine letzte Option sein. Möglicherweise könnte es auch die Schicht stören, die mit dem Garn in Verbindung steht, wenn es im Garn-Client-Modus verwendet wird, obwohl ich nicht sicher bin.
YoYo
Danke für die Vorwarnung. Gibt es eine Möglichkeit, nur 1 JAR zu priorisieren, das in einer älteren Version definitiv auf dem Server vorhanden ist, das Sie jedoch nicht physisch ersetzen können und das Sie nicht verwenden möchten?
Stanislav
1
In diesem Fall könnten Sie es genau so versuchen, wie Sie es vorgeschlagen haben. Ich habe nicht gesagt, dass es ein absolutes Nein ist. Beachten Sie auch, dass die Option als "experimentell" gekennzeichnet ist - eine Warnung, die beachtet werden muss! Es gibt keine sichere Möglichkeit, eine Version einer Bibliothek vor einer anderen zu priorisieren. In einigen Implementierungen wird dies gelöst, indem eine der Bibliotheken in einen anderen Namespace verschoben wird, sodass Sie beide Versionen gleichzeitig verwenden können.
YoYo
1

Weitere konfigurierbare Spark-Optionen für Jars und Klassenpfade im yarnBereitstellungsmodus sind wie folgt:
Aus der Spark-Dokumentation:

spark.yarn.jars

Liste der Bibliotheken mit Spark-Code, die an YARN-Container verteilt werden sollen. Standardmäßig verwendet Spark on YARN lokal installierte Spark-Gläser. Die Spark-Gläser können sich jedoch auch an einem weltweit lesbaren Ort in HDFS befinden. Dadurch kann YARN es auf Knoten zwischenspeichern, sodass es nicht jedes Mal verteilt werden muss, wenn eine Anwendung ausgeführt wird. Um beispielsweise auf Gläser in HDFS zu verweisen, setzen Sie diese Konfiguration auf hdfs: /// some / path. Globs sind erlaubt.

spark.yarn.archive

Ein Archiv mit den erforderlichen Spark-Jars für die Verteilung an den YARN-Cache. Wenn festgelegt, ersetzt diese Konfiguration spark.yarn.jars und das Archiv wird in allen Containern der Anwendung verwendet. Das Archiv sollte JAR-Dateien in seinem Stammverzeichnis enthalten. Wie bei der vorherigen Option kann das Archiv auch auf HDFS gehostet werden, um die Dateiverteilung zu beschleunigen.

Benutzer können diesen Parameter so konfigurieren, dass sie ihre Jars angeben, die im Klassenpfad des Spark-Treibers enthalten sind.

Dunkler Mann
quelle
1

Bei Verwendung von spark-submit mit --master yarn-cluster wird das Anwendungsglas zusammen mit allen in der Option --jars enthaltenen Gläsern automatisch in das Cluster übertragen. Nach --jars angegebene URLs müssen durch Kommas getrennt werden. Diese Liste ist in den Klassenpfaden für Treiber und Executor enthalten

Beispiel:

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

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

Shiva Garg
quelle
0

Die Verwendung ist eingeschränkt --jars: Wenn Sie ein Verzeichnis für den Speicherort der jar/xmlDatei angeben möchten, sind keine Verzeichniserweiterungen zulässig. Dies bedeutet, wenn Sie für jedes Glas einen absoluten Pfad angeben müssen.

Wenn Sie angeben --driver-class-pathund im Garnclustermodus ausführen, wird die Treiberklasse nicht aktualisiert. Wir können überprüfen, ob der Klassenpfad unter spark ui oder spark history server unter tab tab aktualisiert wurde oder nicht.

Option, die für mich funktioniert hat, um Gläser zu übergeben, die Verzeichniserweiterungen enthalten und die im Garnclustermodus funktionieren, war die --confOption. Es ist besser, Treiber- und Executor-Klassenpfade als zu übergeben --conf, wodurch sie dem Spark-Sitzungsobjekt selbst hinzugefügt werden und diese Pfade in der Spark-Konfiguration wiedergegeben werden. Stellen Sie jedoch sicher, dass sich die Gläser im Cluster über denselben Pfad befinden.

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
quelle
Frohes neues Jahr!
YoYo
Frohes Neues Jahr YoYo
Tanveer
0

Während wir Spark-Jobs mit dem Spark-Submit-Dienstprogramm senden, gibt es eine Option --jars. Mit dieser Option können wir eine JAR-Datei an Spark-Anwendungen übergeben.

bala
quelle
Dass es diese —jarOption gibt, wurde im Originalplakat erwähnt und in mehr als einer Antwort ausführlicher besprochen. Es scheint nicht, dass Sie etwas Neues anbieten?
YoYo