Dodaj słoiki do pracy Spark - przesyłanie iskier

158

To prawda ... dużo o tym dyskutowano.

Istnieje jednak wiele niejasności, a niektóre z udzielonych odpowiedzi ... w tym powielanie odniesień do jar w konfiguracji lub opcjach jars / executor / sterownik.

Niejednoznaczne i / lub pominięte szczegóły

W związku z niejednoznacznością, niejasnymi i / lub pominiętymi szczegółami należy wyjaśnić każdą opcję:

  • Jak to wpływa na ClassPath
    • Kierowca
    • Executor (do zadań w toku)
    • Obie
    • Ani trochę
  • Znak rozdzielający: przecinek, dwukropek, średnik
  • Jeśli dostarczone pliki są dystrybuowane automatycznie
    • za zadania (do każdego wykonawcy)
    • dla zdalnego sterownika (jeśli działał w trybie klastra)
  • typ akceptowanego identyfikatora URI: plik lokalny, hdfs, http itp
  • W przypadku skopiowania do wspólnej lokalizacji, gdzie ta lokalizacja jest (hdfs, lokalna?)

Opcje, na które ma to wpływ:

  1. --jars
  2. SparkContext.addJar(...) metoda
  3. SparkContext.addFile(...) metoda
  4. --conf spark.driver.extraClassPath=... lub --driver-class-path ...
  5. --conf spark.driver.extraLibraryPath=...lub --driver-library-path ...
  6. --conf spark.executor.extraClassPath=...
  7. --conf spark.executor.extraLibraryPath=...
  8. nie zapominajmy, że ostatnim parametrem funkcji przesyłania iskier jest również plik .jar.

Wiem, gdzie mogę znaleźć główną dokumentację Spark , a konkretnie o sposobie jej przesyłania , dostępnych opcjach , a także JavaDoc . Jednak pozostawiło mi to sporo dziur, chociaż częściowo też odpowiedziało.

Mam nadzieję, że to nie wszystko jest takie skomplikowane i że ktoś udzieli mi jasnej i zwięzłej odpowiedzi.

Gdybym miał zgadywać z dokumentacji, wydaje się --jars, że metody SparkContext addJari addFilesą tymi, które automatycznie dystrybuują pliki, podczas gdy inne opcje jedynie modyfikują ClassPath.

Czy byłoby bezpiecznie założyć, że dla uproszczenia mogę dodać dodatkowe pliki jar aplikacji, korzystając z 3 głównych opcji w tym samym czasie:

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

Znalazłem fajny artykuł na temat odpowiedzi na inny post . Jednak nic nowego się nie nauczyło. Plakat zawiera dobrą uwagę na temat różnicy między sterownikiem lokalnym (klient przędzy) a sterownikiem zdalnym (grupa przędzy). Zdecydowanie ważne, o czym należy pamiętać.

YoYo
źródło
1
W ramach którego menedżera klastra działasz? Samodzielny / YARN / Mesos?
Yuval Itzchakov
Każdy. Zamierzam to jako wyjaśnienie oryginalnej dokumentacji. Używam głównie samodzielnego klastra, pojedynczej instancji, klienta przędzy, klastra przędzy. Inni mogą używać Mesosa. Wygląda na to, że zrobiłeś na swoim blogu dobre, oryginalne badania na ten temat. Skończyło się na tym, że zrobiłem to samo, co ty - używając modułu cieniującego do stworzenia słoika Ubera, aby uprościć proces wdrażania.
YoYo
1
Opublikuję odpowiedź dotyczącą sposobu wdrażania platformy Spark Standalone, która może wyjaśnić kilka rzeczy.
Yuval Itzchakov
6
Postarałem się odpowiedzieć na wszystkie Twoje pytania. Mam nadzieję, że to pomoże :)
Yuval Itzchakov
@Yuval Itzchakov, tak jak wspomniał Yoyo, ja również używam zacienionego jar, aby spakować wszystkie moje zależności, np. Klasy przypadków i inne pliki jar, których mogę używać. Próbuję zrozumieć, kiedy napotkałbym sytuację, w której potrzebuję wielu słoików. Chodzi mi o to, że zawsze mogę spakować te wiele słoików w jeden słoik Uber. Dlaczego nie mogę dalej żyć z moimi zacienionymi słoikami, które obejmują wszystkie moje zależności?
Sheel Pancholi

Odpowiedzi:

177

ClassPath:

ClassPath zależy od tego, co podasz. Istnieje kilka sposobów ustawienia czegoś w ścieżce klas:

  • spark.driver.extraClassPathlub jest to alias --driver-class-pathdo ustawiania dodatkowych ścieżek klas w węźle, na którym działa sterownik.
  • spark.executor.extraClassPath aby ustawić dodatkową ścieżkę klas w węzłach Worker.

Jeśli chcesz, aby określony plik JAR był wykonywany zarówno na urządzeniu głównym, jak i na robaku, musisz określić je osobno w OBU flagach.

Znak separacji:

Zgodnie z tymi samymi zasadami, co JVM :

  • Linux: dwukropek :
    • na przykład: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar:/opt/prog/aws-java-sdk-1.10.50.jar"
  • Windows: średnik ;
    • na przykład: --conf "spark.driver.extraClassPath=/opt/prog/hadoop-aws-2.7.1.jar;/opt/prog/aws-java-sdk-1.10.50.jar"

Dystrybucja plików:

Zależy to od trybu, w którym wykonujesz swoją pracę:

  1. Tryb klienta - Spark uruchamia serwer HTTP Netty, który dystrybuuje pliki podczas uruchamiania dla każdego węzła roboczego. Możesz zobaczyć, że rozpoczynając pracę w 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. Tryb klastra - w trybie klastra Spark wybrał wiodący węzeł Worker, na którym ma wykonać proces sterownika. Oznacza to, że zadanie nie jest uruchamiane bezpośrednio z węzła głównego. Tutaj Spark nie ustawi serwera HTTP. Musisz ręcznie udostępnić pliki JARS dla wszystkich węzłów roboczych za pośrednictwem HDFS / S3 / innych źródeł, które są dostępne dla wszystkich węzłów.

Akceptowane identyfikatory URI dla plików

W sekcji „Przesyłanie wniosków” dokumentacja Spark dobrze radzi sobie z wyjaśnianiem akceptowanych prefiksów plików:

Podczas korzystania z funkcji wysyłania iskier plik jar aplikacji wraz ze wszystkimi plikami JAR uwzględnionymi w opcji --jars zostaną automatycznie przeniesione do klastra. Spark używa następującego schematu adresu URL, aby umożliwić różne strategie rozpowszechniania słoików:

  • file: - Bezwzględne ścieżki i file: / URI są obsługiwane przez serwer plików HTTP sterownika, a każdy moduł wykonawczy pobiera plik z serwera HTTP sterownika.
  • hdfs :, http :, https :, ftp: - te pliki rozwijane i JAR z URI zgodnie z oczekiwaniami
  • local: - oczekuje się, że identyfikator URI zaczynający się od local: / będzie istniał jako plik lokalny w każdym węźle roboczym. Oznacza to, że żadne operacje we / wy sieci nie zostaną poniesione i działa dobrze w przypadku dużych plików / plików JAR, które są wysyłane do każdego pracownika lub udostępniane przez NFS, GlusterFS itp.

Należy pamiętać, że pliki JAR i pliki są kopiowane do katalogu roboczego dla każdego SparkContext w węzłach wykonawczych.

Jak zauważono, pliki JAR są kopiowane do katalogu roboczego dla każdego węzła roboczego . Gdzie to dokładnie jest? Jest to zwykle pod /var/run/spark/workzobaczysz je tak:

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

A kiedy zajrzysz do środka, zobaczysz wszystkie wdrożone pliki JAR:

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

Dotyczy opcji:

Najważniejszą rzeczą do zrozumienia jest priorytet . Jeśli przekażesz jakąkolwiek właściwość za pomocą kodu, będzie ona miała pierwszeństwo przed dowolną opcją określoną za pomocą spark-submit. Jest to wspomniane w dokumentacji Spark:

Wszelkie wartości określone jako flagi lub w pliku właściwości zostaną przekazane do aplikacji i scalone z wartościami określonymi za pośrednictwem SparkConf. Właściwości ustawione bezpośrednio w SparkConf mają najwyższy priorytet , następnie flagi przekazane do funkcji Spark-submit lub Spark-Shell, a następnie opcje w pliku spark-defaults.conf

Dlatego upewnij się, że ustawiłeś te wartości we właściwych miejscach, aby nie zdziwić się, gdy jedna ma pierwszeństwo przed drugą.

Przeanalizujmy każdą opcję, o której mowa:

  • --jarsvs SparkContext.addJar: Są identyczne, tylko jeden jest ustawiany przez przesyłanie iskry, a drugi przez kod. Wybierz ten, który bardziej Ci odpowiada. Jedną ważną rzeczą do zapamiętania jest to, że użycie którejkolwiek z tych opcji nie dodaje pliku JAR do ścieżki klas sterownika / modułu wykonawczego , musisz jawnie dodać je za pomocą extraClassPathkonfiguracji obu.
  • SparkContext.addJarvs SparkContext.addFile: Użyj tego pierwszego, gdy masz zależność, która musi być używana z twoim kodem. Użyj tego ostatniego, gdy chcesz po prostu przekazać dowolny plik do węzłów roboczych, co nie jest zależnością czasu wykonywania w kodzie.
  • --conf spark.driver.extraClassPath=...lub --driver-class-path: To są aliasy, nie ma znaczenia, który wybierzesz
  • --conf spark.driver.extraLibraryPath=..., or --driver-library-path ... Jak wyżej, aliasy.
  • --conf spark.executor.extraClassPath=...: Użyj tego, gdy masz zależność, której nie można dołączyć do pliku JAR typu uber (na przykład z powodu konfliktów czasu kompilacji między wersjami biblioteki) i którą musisz załadować w czasie wykonywania.
  • --conf spark.executor.extraLibraryPath=...Jest to java.library.pathopcja dla maszyny JVM. Użyj tego, gdy potrzebujesz ścieżki biblioteki widocznej dla maszyny JVM.

Czy byłoby bezpiecznie założyć, że dla uproszczenia mogę dodać dodatkowe pliki jar aplikacji, korzystając z 3 głównych opcji w tym samym czasie:

Możesz bezpiecznie założyć to tylko w trybie klienta, a nie w trybie klastrowym. Jak powiedziałem wcześniej. Ponadto podany przykład ma kilka zbędnych argumentów. Na przykład przekazywanie plików JAR do --driver-library-pathjest bezużyteczne, musisz je przekazać, extraClassPathjeśli chcesz, aby znalazły się na Twojej ścieżce klas. Ostatecznie to, co chcesz zrobić, gdy wdrażasz zewnętrzne pliki JAR zarówno na sterowniku, jak i na pracowniku, to:

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
źródło
4
Świetna i wyczerpująca odpowiedź. Dziękuję Ci. Czy możesz również opowiedzieć więcej o sprawdzonych metodach wdrażania z uber JAR w porównaniu z zależnościami poza JAR (biblioteki w folderze zewnętrznym i wymienione w MANIFEST.MFpliku)?
jsosnowski
2
@jsosnowski Zwykle korzystam z zewnętrznych plików JAR tylko wtedy, gdy występują konflikty, które są bardzo skomplikowane do rozwiązania za pomocą mojego pliku JAR Uber. Zwykle osiągam po prostu używając SBT assemblyMergeStrategyi wybierając klasy, których potrzebuję, jeśli występują konflikty. Generalnie polecam to samo.
Yuval Itzchakov
9
@ yuval-itzchakov Dzięki za świetną odpowiedź, bardzo pomocny. Chciałbym podkreślić jedną kwestię, aby pomóc innym, którzy mogli popełnić ten sam błąd co ja. Argument --jars przenosi tylko pliki JAR do każdej maszyny w klastrze. NIE nakazuje Sparkowi użycia ich w przeszukiwaniu ścieżki klas. --Driver-class-path (lub podobne argumenty lub parametry konfiguracyjne) są również wymagane. Początkowo myślałem, że to alternatywne sposoby robienia tego samego.
Tim Ryan,
1
@TimRyan Zdecydowanie. Jeśli spojrzysz na ostatnią część odpowiedzi, przekazuję jars zarówno do --jarsflagi, jak i ścieżki klasy sterownika / executora.
Yuval Itzchakov
1
W końcu znalazłem sposób wstrzykiwania zmiennych środowiskowych do zeppelin-env.shi dodawania --jarsdo SPARK_SUBMIT_OPTIONS. To się udało. Format URI, którego używam, to --jars=local:///mnt/dir/file.jar.
Mike
4

Innym podejściem w programie spark 2.1.0jest użycie --conf spark.driver.userClassPathFirst=truepodczas wysyłania iskry, co zmienia priorytet obciążenia zależności, a tym samym zachowanie iskry, poprzez nadanie priorytetu jars, które użytkownik dodaje do ścieżki klasy za pomocą --jarsopcji.

Stanislav
źródło
2
Będziesz musiał z tym uważać - ponieważ można w ten sposób złamać iskrę. Powinno to być ostatnią opcją. Potencjalnie może to kolidować z warstwą stykającą się z przędzą również podczas używania w trybie przędzy-klienta, chociaż nie jestem pewien.
YoYo
Dziękuję za ostrzeżenia. Czy istnieje sposób na nadanie priorytetu tylko 1 słoikowi, który z pewnością istnieje na serwerze w starszej wersji, ale nie można go fizycznie zastąpić i wiesz, że nie chcesz go używać?
Stanislav
1
Myślę, że w takim przypadku możesz spróbować dokładnie tak, jak sugerowałeś. Nie powiedziałem, że to absolutne nie. Pamiętaj również, że opcja jest oznaczona jako „eksperymentalna” - ostrzeżenie, na które należy zwrócić uwagę! Nie ma bezpiecznego sposobu nadawania priorytetu jednej wersji biblioteki względem innej. W niektórych implementacjach można to rozwiązać, przenosząc jedną z bibliotek do innej przestrzeni nazw, dzięki czemu można używać obu wersji w tym samym czasie.
YoYo
1

Inne konfigurowalne opcje Spark dotyczące słoików i ścieżki klas, w przypadku yarntrybu wdrażania, są następujące
Z dokumentacji Spark,

spark.yarn.jars

Lista bibliotek zawierających kod Spark do dystrybucji do kontenerów YARN. Domyślnie Spark on YARN będzie używać słoików Spark zainstalowanych lokalnie, ale słoiki Spark mogą również znajdować się w czytelnej dla wszystkich lokalizacji na HDFS. Pozwala to YARN na buforowanie go w węzłach, dzięki czemu nie trzeba go dystrybuować za każdym razem, gdy aplikacja jest uruchamiana. Na przykład, aby wskazać pliki jar na HDFS, ustaw tę konfigurację na hdfs: /// some / path. Kulki są dozwolone.

spark.yarn.archive

Archiwum zawierające potrzebne słoiki Spark do dystrybucji do pamięci podręcznej YARN. Jeśli jest ustawiona, ta konfiguracja zastępuje spark.yarn.jars, a archiwum jest używane we wszystkich kontenerach aplikacji. Archiwum powinno zawierać pliki jar w swoim katalogu głównym. Podobnie jak w przypadku poprzedniej opcji, archiwum można również hostować na HDFS, aby przyspieszyć dystrybucję plików.

Użytkownicy mogą skonfigurować ten parametr, aby określić swoje pliki słoików, które zostaną uwzględnione w ścieżce klas sterownika Spark.

DaRkMaN
źródło
1

Podczas korzystania z funkcji spark-submit z --master yarn-cluster, jar aplikacji wraz ze wszystkimi słoikami dołączonymi do opcji --jars zostaną automatycznie przeniesione do klastra. Adresy URL podane po --jars muszą być oddzielone przecinkami. Ta lista jest zawarta w ścieżkach klas sterownika i modułu wykonawczego

Przykład:

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
źródło
0

Istnieje ograniczenie dotyczące używania --jars: jeśli chcesz określić katalog dla lokalizacji jar/xmlpliku, nie zezwala na rozszerzenia katalogów. Oznacza to, że musisz określić bezwzględną ścieżkę dla każdego pliku jar.

Jeśli określisz --driver-class-pathi wykonujesz w trybie klastra przędzy, klasa sterownika nie zostanie zaktualizowana. Możemy sprawdzić, czy ścieżka klasy jest aktualizowana, czy nie, w Spark ui lub Spark History Server w środowisku zakładek.

Opcją, która działała dla mnie do przekazywania słoików, które zawierają rozszerzenia katalogów i która działała w trybie klastra przędzy, była --confopcja. Lepiej jest przekazywać ścieżki sterownika i klasy wykonawczej jako --conf, co powoduje dodanie ich do samego obiektu sesji iskrowej, a te ścieżki są odzwierciedlane w konfiguracji platformy Spark. Ale pamiętaj, aby umieścić słoiki na tej samej ścieżce w klastrze.

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
źródło
Szczęśliwego Nowego Roku!
YoYo
Szczęśliwego Nowego Roku YoYo
Tanveer
0

Chociaż wysyłamy zadania związane z iskrą za pomocą narzędzia do przesyłania iskier, istnieje opcja --jars. Korzystając z tej opcji, możemy przekazać plik jar do aplikacji Spark.

bala
źródło
O tym, że istnieje ta —jaropcja, wspomniał oryginalny plakat, a dodatkowo omówiono ją bardziej szczegółowo w więcej niż jednej odpowiedzi. Nie wygląda na to, że udostępniasz coś nowego?
YoYo