Spark auf YARN konfigurieren

Habr, hallo! Gestern am Meetup für Apache Spark, von den Jungs von Rambler&Co, es gab ziemlich viele Fragen von Teilnehmern im Zusammenhang mit der Konfiguration dieses Tools. Wir beschlossen, in seine Fußstapfen zu treten und unsere Erfahrungen zu teilen. Das Thema ist nicht einfach – deshalb laden wir Sie ein, Ihre Erfahrungen in den Kommentaren zu teilen, vielleicht verstehen und verwenden wir auch etwas falsch.

Eine kleine Einführung in die Verwendung von Spark. Wir haben ein dreimonatiges Programm „Big-Data-Spezialist“und im zweiten Modul arbeiten unsere Teilnehmer an diesem Instrument. Dementsprechend besteht unsere Aufgabe als Organisatoren darin, den Cluster für den Einsatz in einem solchen Fall vorzubereiten.

Die Besonderheit unserer Nutzung besteht darin, dass die Anzahl der Personen, die gleichzeitig an Spark arbeiten, der gesamten Gruppe entsprechen kann. Zum Beispiel bei einem Seminar, wenn alle gleichzeitig etwas ausprobieren und unserem Lehrer nachsprechen. Und das ist nicht viel – manchmal bis zu 40 Leute. Es gibt wahrscheinlich nicht viele Unternehmen auf der Welt, die mit einem solchen Anwendungsfall konfrontiert sind.

Als nächstes erzähle ich Ihnen, wie und warum wir bestimmte Konfigurationsparameter ausgewählt haben.

Fangen wir ganz von vorne an. Spark bietet drei Optionen für die Ausführung in einem Cluster: eigenständig, mit Mesos und mit YARN. Wir haben uns für die dritte Option entschieden, weil sie für uns sinnvoll war. Wir haben bereits einen Hadoop-Cluster. Unsere Teilnehmer sind mit seiner Architektur bereits bestens vertraut. Lassen Sie uns YARN verwenden.

spark.master=yarn

Noch interessanter. Jede dieser drei Bereitstellungsoptionen verfügt über zwei Bereitstellungsoptionen: Client und Cluster. Ausgehend von Dokumentation Aus verschiedenen Links im Internet können wir schließen, dass der Client für interaktives Arbeiten geeignet ist – beispielsweise über Jupyter Notebook – und Cluster eher für Produktionslösungen geeignet ist. In unserem Fall waren wir an interaktiver Arbeit interessiert, daher:

spark.deploy-mode=client

Im Allgemeinen wird Spark von nun an irgendwie mit YARN funktionieren, aber das hat uns nicht gereicht. Da wir ein Programm zum Thema Big Data haben, hatten die Teilnehmer manchmal nicht genug von dem, was im Rahmen einer gleichmäßigen Ressourcenaufteilung gewonnen wurde. Und dann haben wir etwas Interessantes entdeckt – die dynamische Ressourcenzuweisung. Kurz gesagt, der Punkt ist folgender: Wenn Sie eine schwierige Aufgabe haben und der Cluster frei ist (z. B. morgens), kann Spark Ihnen mit dieser Option zusätzliche Ressourcen zur Verfügung stellen. Dort wird die Notwendigkeit nach einer raffinierten Formel berechnet. Wir gehen nicht auf Details ein – es funktioniert gut.

spark.dynamicAllocation.enabled=true

Wir haben diesen Parameter festgelegt und beim Start stürzte Spark ab und startete nicht. Das stimmt, denn ich musste es lesen Dokumentation vorsichtiger. Darin heißt es, dass Sie, damit alles in Ordnung ist, auch einen zusätzlichen Parameter aktivieren müssen.

spark.shuffle.service.enabled=true

Warum wird es benötigt? Wenn unser Job nicht mehr so ​​viele Ressourcen benötigt, sollte Spark sie in den gemeinsamen Pool zurückführen. Die zeitaufwändigste Phase in fast jeder MapReduce-Aufgabe ist die Shuffle-Phase. Mit diesem Parameter können Sie die in dieser Phase generierten Daten speichern und die Ausführenden entsprechend freigeben. Und der Testamentsvollstrecker ist der Prozess, der alles auf den Arbeiter ausrechnet. Es verfügt über eine bestimmte Anzahl von Prozessorkernen und eine bestimmte Menge an Speicher.

Dieser Parameter wurde hinzugefügt. Alles schien zu funktionieren. Es fiel auf, dass den Teilnehmern tatsächlich mehr Ressourcen zur Verfügung gestellt wurden, wenn sie diese brauchten. Es trat jedoch ein anderes Problem auf: Irgendwann wachten andere Teilnehmer auf und wollten ebenfalls Spark nutzen, aber dort war alles beschäftigt und sie waren unzufrieden. Sie können verstanden werden. Wir begannen, uns die Dokumentation anzusehen. Es stellte sich heraus, dass es noch eine Reihe weiterer Parameter gibt, mit denen der Prozess beeinflusst werden kann. Wenn sich der Executor beispielsweise im Standby-Modus befindet, nach welcher Zeit können ihm dann Ressourcen entnommen werden?

spark.dynamicAllocation.executorIdleTimeout=120s

Wenn Ihre Testamentsvollstrecker in unserem Fall zwei Minuten lang nichts tun, geben Sie sie bitte in den gemeinsamen Pool zurück. Dieser Parameter reichte jedoch nicht immer aus. Es war klar, dass die Person schon lange nichts getan hatte und keine Ressourcen freigesetzt wurden. Es stellte sich heraus, dass es auch einen speziellen Parameter gibt – nach welcher Zeit Executoren ausgewählt werden sollen, die zwischengespeicherte Daten enthalten. Standardmäßig war dieser Parameter unendlich! Wir haben es korrigiert.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

Das heißt, wenn Ihre Testamentsvollstrecker 5 Minuten lang nichts tun, geben Sie sie in den gemeinsamen Pool. In diesem Modus ist die Geschwindigkeit der Freigabe und Ausgabe von Ressourcen für eine große Anzahl von Benutzern angemessen geworden. Die Unzufriedenheit hat abgenommen. Aber wir haben beschlossen, noch einen Schritt weiter zu gehen und die maximale Anzahl von Ausführenden pro Anwendung zu begrenzen – im Wesentlichen pro Programmteilnehmer.

spark.dynamicAllocation.maxExecutors=19

Nun gibt es natürlich auch unzufriedene Leute auf der anderen Seite – „Der Cluster liegt im Leerlauf, und ich habe nur 19 Testamentsvollstrecker“, aber was kann man tun? Wir brauchen eine Art richtige Balance. Man kann nicht alle glücklich machen.

Und noch eine kleine Geschichte, die sich auf die Besonderheiten unseres Falles bezieht. Irgendwie kamen mehrere Leute zu spät zu einer praktischen Lektion, und aus irgendeinem Grund startete Spark für sie nicht. Wir haben uns die Menge an freien Ressourcen angesehen – sie scheint vorhanden zu sein. Spark sollte starten. Glücklicherweise war die Dokumentation zu diesem Zeitpunkt bereits irgendwo zum Subcortex hinzugefügt worden, und wir erinnerten uns daran, dass Spark beim Starten nach einem Port sucht, auf dem es gestartet werden kann. Wenn der erste Port im Bereich belegt ist, wechselt er der Reihe nach zum nächsten. Wenn es frei ist, fängt es ein. Und es gibt einen Parameter, der die maximale Anzahl der Versuche dafür angibt. Der Standardwert ist 16. Die Anzahl ist geringer als die Anzahl der Personen in unserer Gruppe im Unterricht. Dementsprechend gab Spark nach 16 Versuchen auf und meinte, ich könne nicht starten. Wir haben diese Einstellung korrigiert.

spark.port.maxRetries=50

Als nächstes erzähle ich Ihnen von einigen Einstellungen, die nicht sehr mit den Besonderheiten unseres Falles zusammenhängen.

Um Spark schneller zu starten, empfiehlt es sich, den jars-Ordner im SPARK_HOME-Home-Verzeichnis zu archivieren und auf HDFS abzulegen. Dann wird er keine Zeit damit verschwenden, diese Jarniks durch Arbeiter zu beladen.

spark.yarn.archive=hdfs:///tmp/spark-archive.zip

Für einen schnelleren Betrieb wird außerdem empfohlen, Kryo als Serialisierer zu verwenden. Es ist optimierter als das Standardmodell.

spark.serializer=org.apache.spark.serializer.KryoSerializer

Und es gibt auch ein seit langem bestehendes Problem mit Spark, dass es oft aus dem Speicher abstürzt. Dies geschieht oft in dem Moment, in dem die Arbeiter alles berechnet haben und das Ergebnis an den Fahrer senden. Wir haben diesen Parameter für uns vergrößert. Standardmäßig ist es 1 GB, wir haben es auf 3 festgelegt.

spark.driver.maxResultSize=3072

Und schließlich als Nachtisch. So aktualisieren Sie Spark auf Version 2.1 in der HortonWorks-Distribution – HDP 2.5.3.0. Diese Version von HDP enthält eine vorinstallierte Version 2.0, aber wir haben einmal selbst entschieden, dass Spark ziemlich aktiv weiterentwickelt wird und jede neue Version einige Fehler behebt und zusätzliche Funktionen bereitstellt, auch für die Python-API, also haben wir entschieden, was nötig ist erledigt werden muss, ist ein Update.

Die Version für Hadoop 2.7 wurde von der offiziellen Website heruntergeladen. Habe es entpackt und im HDP-Ordner abgelegt. Wir haben die Symlinks nach Bedarf installiert. Wir starten es – es startet nicht. Schreibt einen sehr seltsamen Fehler.

java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig

Nachdem wir gegoogelt hatten, fanden wir heraus, dass Spark beschlossen hatte, nicht bis zur Geburt von Hadoop zu warten, sondern die neue Version von Jersey zu verwenden. Sie selbst streiten in JIRA miteinander über dieses Thema. Die Lösung war das Herunterladen Trikotversion 1.17.1. Legen Sie dies im Ordner „jars“ in SPARK_HOME ab, komprimieren Sie es erneut und laden Sie es auf HDFS hoch.

Wir haben diesen Fehler umgangen, aber es ist ein neuer und ziemlich vereinfachter Fehler entstanden.

org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master

Gleichzeitig versuchen wir, Version 2.0 auszuführen – alles ist in Ordnung. Versuchen Sie zu erraten, was los ist. Wir haben uns die Protokolle dieser Anwendung angesehen und etwa Folgendes gesehen:

/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jar

Im Allgemeinen wurde hdp.version aus irgendeinem Grund nicht aufgelöst. Nachdem wir gegoogelt hatten, fanden wir eine Lösung. Sie müssen zu den YARN-Einstellungen in Ambari gehen und dort einen Parameter zur benutzerdefinierten Garn-Site hinzufügen:

hdp.version=2.5.3.0-37

Diese Magie half und Spark machte sich auf den Weg. Wir haben mehrere unserer Jupyter-Laptops getestet. Alles arbeitet. Wir sind bereit für die erste Spark-Lektion am Samstag (morgen)!

UPD. Während des Unterrichts kam ein weiteres Problem zutage. Irgendwann stellte YARN die Bereitstellung von Containern für Spark ein. In YARN musste der Parameter korrigiert werden, der standardmäßig 0.2 war:

yarn.scheduler.capacity.maximum-am-resource-percent=0.8

Das heißt, nur 20 % der Ressourcen beteiligten sich an der Ressourcenverteilung. Nachdem wir die Parameter geändert hatten, haben wir YARN neu geladen. Das Problem wurde gelöst und auch die übrigen Teilnehmer konnten Spark Context ausführen.

Source: habr.com

Kommentar hinzufügen