Aggiungi vasetti a un processo Spark - spark-submit


158

È vero ... è stato discusso parecchio.

Tuttavia, vi è molta ambiguità e alcune delle risposte fornite ... tra cui la duplicazione dei riferimenti jar nella configurazione o nelle opzioni di vasetti / esecutore / driver.

I dettagli ambigui e / o omessi

A seguito di ambiguità, i dettagli non chiari e / o omessi devono essere chiariti per ogni opzione:

  • Come è interessato ClassPath
    • autista
    • Executor (per attività in esecuzione)
    • Tutti e due
    • Affatto
  • Carattere di separazione: virgola, due punti, punto e virgola
  • Se i file forniti vengono distribuiti automaticamente
    • per i compiti (per ciascun esecutore)
    • per il driver remoto (se eseguito in modalità cluster)
  • tipo di URI accettato: file locale, hdfs, http, ecc
  • Se copiato in una posizione comune, dove si trova quella posizione (hdfs, locale?)

Le opzioni alle quali influisce:

  1. --jars
  2. SparkContext.addJar(...) metodo
  3. SparkContext.addFile(...) metodo
  4. --conf spark.driver.extraClassPath=... o --driver-class-path ...
  5. --conf spark.driver.extraLibraryPath=..., o --driver-library-path ...
  6. --conf spark.executor.extraClassPath=...
  7. --conf spark.executor.extraLibraryPath=...
  8. per non dimenticare, l'ultimo parametro di spark-submit è anche un file .jar.

Sono a conoscenza di dove posso trovare la documentazione principale di Spark e in particolare su come inviare , le opzioni disponibili e anche JavaDoc . Tuttavia, ciò mi ha lasciato alcuni buchi, anche se ha risposto anche parzialmente.

Spero che non sia poi così complesso e che qualcuno possa darmi una risposta chiara e concisa.

Se dovessi indovinare dalla documentazione, sembra che --jarsi metodi SparkContext addJare addFilesiano quelli che distribuiranno automaticamente i file, mentre le altre opzioni modificheranno semplicemente ClassPath.

Sarebbe sicuro supporre che, per semplicità, posso aggiungere ulteriori file jar dell'applicazione usando contemporaneamente le 3 opzioni principali:

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

Ho trovato un bell'articolo su una risposta a un'altra pubblicazione . Tuttavia nulla di nuovo imparato. Il poster fa una buona osservazione sulla differenza tra driver locale (client di thread) e driver remoto (cluster di thread). Decisamente importante da tenere a mente.


1
In quale gestore di cluster stai eseguendo? Standalone / filato / Mesos?
Yuval Itzchakov,

Qualunque. Intendo questo come un chiarimento alla documentazione originale. Uso principalmente cluster autonomi, istanza singola, client-thread, cluster-thread. Altri potrebbero usare Mesos. Sembra che tu abbia fatto una buona ricerca originale sul tuo blog su questo. Ho finito per fare quasi lo stesso con te: usare uno shader per creare un vaso Uber per semplificare il mio processo di distribuzione.
YoYo,

1
Invierò una risposta su come implementiamo Spark Standalone, che potrebbe chiarire alcune cose.
Yuval Itzchakov,

6
Ho fatto uno sforzo per rispondere a tutte le tue domande. Spero che aiuti :)
Yuval Itzchakov,

@Yuval Itzchakov, proprio come menzionato da Yoyo, anch'io uso un vaso ombreggiato per raggruppare tutte le mie dipendenze, ad esempio classi di casi e altri vasi che potrei usare. Sto cercando di capire quando dovrei imbattermi in una situazione in cui ho bisogno di più vasetti. Voglio dire, posso sempre raggruppare quei vasetti multipli in 1 barattolo superlativo. Perché non posso continuare a vivere con i miei barattoli ombreggiati che raccolgono tutte le mie dipendenze?
Sheel Pancholi,

Risposte:


177

ClassPath:

ClassPath è interessato a seconda di ciò che fornisci. Ci sono un paio di modi per impostare qualcosa sul percorso di classe:

  • spark.driver.extraClassPathoppure è alias --driver-class-pathimpostare percorsi di classe extra sul nodo che esegue il driver.
  • spark.executor.extraClassPath per impostare un percorso di classe extra sui nodi Worker.

Se si desidera effettuare un determinato JAR sia sul Master che sul Worker, è necessario specificarli separatamente in ENTRAMBI i flag.

Carattere di separazione:

Seguendo le stesse regole della JVM :

  • Linux: i due punti :
    • per esempio: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar:/opt/prog/aws-java-sdk-1.10.50.jar"
  • Windows: un punto e virgola ;
    • per esempio: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar;/opt/prog/aws-java-sdk-1.10.50.jar"

Distribuzione dei file:

Questo dipende dalla modalità in cui stai eseguendo il tuo lavoro:

  1. Modalità client: Spark avvia un server HTTP Netty che distribuisce i file all'avvio per ciascuno dei nodi di lavoro. Puoi vederlo quando avvii il tuo lavoro 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. Modalità cluster: in modalità cluster spark ha selezionato un nodo Worker leader su cui eseguire il processo Driver. Ciò significa che il lavoro non è in esecuzione direttamente dal nodo principale. Qui, Spark non imposterà un server HTTP. Devi rendere manualmente i tuoi JARS disponibili a tutto il nodo di lavoro tramite HDFS / S3 / Altre fonti che sono disponibili per tutti i nodi.

URI accettati per i file

In "Invio di applicazioni" , la documentazione Spark fa un buon lavoro nel spiegare i prefissi accettati per i file:

Quando si utilizza spark-submit, il vaso dell'applicazione insieme a tutti i vasetti inclusi con l'opzione --jars verranno automaticamente trasferiti al cluster. Spark utilizza il seguente schema URL per consentire diverse strategie per la diffusione di vasetti:

  • file: - Percorsi assoluti e file: / URI sono serviti dal file server HTTP del driver e ogni esecutore estrae il file dal server HTTP del driver.
  • hdfs :, http :, https :, ftp: - questi pull down file e JAR dall'URI come previsto
  • local: - un URI che inizia con local: / dovrebbe esistere come file locale su ciascun nodo di lavoro. Ciò significa che non si verificherà alcun IO di rete e funziona bene per file / JAR di grandi dimensioni che vengono inviati a ciascun lavoratore o condivisi tramite NFS, GlusterFS, ecc.

Notare che JAR e file vengono copiati nella directory di lavoro per ogni SparkContext sui nodi dell'esecutore.

Come notato, i JAR vengono copiati nella directory di lavoro per ciascun nodo di lavoro. Dov'è esattamente quello? Di solito è sotto /var/run/spark/work, li vedrai così:

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

E quando guardi dentro, vedrai tutti i JAR che hai schierato lungo:

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

Opzioni interessate:

La cosa più importante da capire è la priorità . Se si passa una proprietà tramite il codice, avrà la precedenza su qualsiasi opzione specificata tramite spark-submit. Questo è menzionato nella documentazione Spark:

Tutti i valori specificati come flag o nel file delle proprietà verranno passati all'applicazione e uniti a quelli specificati tramite SparkConf. Le proprietà impostate direttamente su SparkConf hanno la massima priorità , quindi i flag passati a spark-submit o spark-shell, quindi le opzioni nel file spark-defaults.conf

Quindi assicurati di impostare quei valori nei posti giusti, in modo da non essere sorpreso quando uno ha la priorità sull'altro.

Analizziamo ogni opzione in questione:

  • --jarsvs SparkContext.addJar: sono identici, solo uno è impostato tramite spark submit e uno tramite codice. Scegli quello che ti piace di più. Una cosa importante da notare è che l'utilizzo di una di queste opzioni non aggiunge il JAR al percorso di classe del tuo driver / esecutore , dovrai aggiungerli esplicitamente usando la extraClassPathconfigurazione su entrambi.
  • SparkContext.addJarvs SparkContext.addFile: usa il primo quando hai una dipendenza che deve essere usata con il tuo codice. Utilizzare quest'ultimo quando si desidera semplicemente passare un file arbitrario ai nodi di lavoro, che non è una dipendenza runtime nel codice.
  • --conf spark.driver.extraClassPath=...oppure --driver-class-path: questi sono alias, non importa quale scegli
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... Come sopra, alias.
  • --conf spark.executor.extraClassPath=...: Utilizzare questa opzione quando si ha una dipendenza che non può essere inclusa in un JAR superar (ad esempio perché ci sono conflitti di tempo di compilazione tra le versioni della libreria) e che è necessario caricare in fase di esecuzione.
  • --conf spark.executor.extraLibraryPath=...Questo è passato come java.library.pathopzione per la JVM. Usalo quando hai bisogno di un percorso di libreria visibile alla JVM.

Sarebbe sicuro supporre che, per semplicità, posso aggiungere ulteriori file jar dell'applicazione usando contemporaneamente le 3 opzioni principali:

Puoi assumerlo in sicurezza solo per la modalità Client, non per la modalità Cluster. Come ho già detto. Inoltre, l'esempio che hai fornito ha alcuni argomenti ridondanti. Ad esempio, passare i JAR a --driver-library-pathè inutile, è necessario passarli a extraClassPathse si desidera che siano sul tuo percorso di classe. In definitiva, ciò che si desidera fare quando si distribuiscono JAR esterni sia sul driver che sul lavoratore è:

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

4
Ottima e completa risposta. Grazie. Potresti anche dire di più sulle migliori pratiche nella distribuzione con JAR super vs dipendenze al di fuori di JAR (librerie nella cartella esterna ed elencate nel MANIFEST.MFfile)?
jsosnowski,

2
@jsosnowski Di solito, rimando all'utilizzo di vasetti esterni rimango solo quando ci sono conflitti che sono molto complessi da risolvere con il mio super JAR. Di solito ci riesco semplicemente usando SBT assemblyMergeStrategye selezionando le classi di cui ho bisogno in caso di conflitti. In genere consiglierei lo stesso.
Yuval Itzchakov,

9
@ yuval-itzchakov Grazie per l'ottima risposta, molto utile. Un punto che vorrei sottolineare per aiutare gli altri che potrebbero aver commesso lo stesso errore. L'argomento --jars trasporta solo i barattoli su ogni macchina nel cluster. NON dice a spark di usarli nella ricerca del percorso di classe. Sono richiesti anche --driver-class-path (o argomenti simili o parametri di configurazione). Inizialmente pensavo che fossero modi alternativi di fare la stessa cosa.
Tim Ryan,

1
@TimRyan Sicuramente. Se guardi l'ultima parte della risposta, passo i vasetti sia al --jarsflag che al percorso della classe driver / esecutore.
Yuval Itzchakov,

1
Alla fine ho trovato come iniettare variabili d'ambiente in zeppelin-env.she ha aggiunto --jarsa SPARK_SUBMIT_OPTIONS. Ha funzionato Il formato URI che uso è --jars=local:///mnt/dir/file.jar.
Mike,

4

Un altro approccio spark 2.1.0consiste nell'utilizzare --conf spark.driver.userClassPathFirst=truedurante spark-submit che modifica la priorità del carico di dipendenza, e quindi il comportamento del spark-job, dando priorità ai barattoli che l'utente sta aggiungendo al percorso di classe con l' --jarsopzione.


2
Dovrai stare attento con quello - poiché è possibile rompere la scintilla facendo così. Questa dovrebbe essere un'ultima soluzione. Potenzialmente potrebbe interferire con lo strato che si interfaccia con il filo anche quando si utilizza in modalità client filo, anche se non sono sicuro.
YoYo

Grazie per il testa a testa. Esiste un modo per dare la priorità solo a 1 jar, che esiste sicuramente nel server in una versione precedente ma non è possibile sostituirlo fisicamente e si sa che non si desidera utilizzare?
Stanislav,

1
Immagino che in quel caso potresti provare esattamente come hai suggerito. Non ho detto che era un no assoluto. Ricorda inoltre che l'opzione è contrassegnata come "sperimentale": un avvertimento da tenere in considerazione! Non esiste un modo sicuro per stabilire le priorità di una versione di una libreria rispetto a un'altra. In alcune implementazioni, questo viene risolto spostando una delle librerie in uno spazio dei nomi diverso, in modo da poter utilizzare entrambe le versioni contemporaneamente.
YoYo

1

Altre opzioni Spark configurabili relative a vasetti e percorso di classe, in caso di yarnmodalità di distribuzione sono le seguenti
Dalla documentazione di Spark,

spark.yarn.jars

Elenco delle librerie contenenti il ​​codice Spark da distribuire ai contenitori YARN. Per impostazione predefinita, Spark su YARN utilizzerà i barattoli Spark installati localmente, ma i barattoli Spark possono anche essere in una posizione leggibile in tutto il mondo su HDFS. Ciò consente a YARN di memorizzarlo nella cache sui nodi in modo che non debba essere distribuito ogni volta che viene eseguita un'applicazione. Per puntare ai vasetti su HDFS, ad esempio, impostare questa configurazione su hdfs: /// some / path. Sono ammessi i globi.

spark.yarn.archive

Un archivio contenente i barattoli Spark necessari per la distribuzione nella cache YARN. Se impostata, questa configurazione sostituisce spark.yarn.jars e l'archivio viene utilizzato in tutti i contenitori dell'applicazione. L'archivio dovrebbe contenere file jar nella sua directory principale. Come con l'opzione precedente, l'archivio può anche essere ospitato su HDFS per accelerare la distribuzione dei file.

Gli utenti possono configurare questo parametro per specificare i loro vasetti, che inturn viene incluso nel percorso di classe del driver Spark.


1

Quando si utilizza spark-submit con --master thread-cluster, il vaso dell'applicazione insieme a tutti i vasetti inclusi con l'opzione --jars verranno automaticamente trasferiti al cluster. Gli URL forniti dopo --jars devono essere separati da virgole. Tale elenco è incluso nei percorsi di classe del driver e dell'esecutore

Esempio :

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


0

Vi sono restrizioni sull'uso --jars: se si desidera specificare una directory per l'ubicazione del jar/xmlfile, non consente espansioni di directory. Ciò significa che è necessario specificare il percorso assoluto per ciascun vaso.

Se si specifica --driver-class-pathe si esegue in modalità cluster di filati, la classe del driver non viene aggiornata. Siamo in grado di verificare se il percorso della classe viene aggiornato o meno in Spark UI o Spark History Server in ambiente Tab.

L'opzione che ha funzionato per me per passare vasi che contengono espansioni di directory e che ha funzionato in modalità cluster di filati è stata --confun'opzione. È meglio passare i percorsi delle classi di driver ed esecutori come --conf, che li aggiunge all'oggetto della sessione spark stesso e quei percorsi si riflettono su Spark Configuration. Ma assicurati di mettere i vasetti sullo stesso percorso attraverso il 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

Felice anno nuovo!
YoYo

Buon anno YoYo
Tanveer

0

Mentre inviamo i lavori spark utilizzando l'utilità spark-submit, esiste un'opzione --jars. Usando questa opzione, possiamo passare il file jar alle applicazioni spark.


Che questa —jaropzione sia stata menzionata dal poster originale, è stata discussa in modo molto più dettagliato da più di una risposta. Non sembra che tu stia fornendo qualcosa di nuovo?
YoYo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.