Khabr, hallo! Gestern auf , gab es viele Fragen von den Teilnehmern, die mit der Konfiguration dieses Tools zu tun hatten. Wir haben beschlossen, unser Wissen darĂŒber zu teilen. Das Thema ist nicht einfach, deshalb schlagen wir vor, auch in den Kommentaren Erfahrungen auszutauschen. Vielleicht verstehen wir auch nicht alles richtig oder verwenden es falsch.
Eine kurze EinfĂŒhrung â wie wir Spark verwenden. Wir haben ein dreimonatiges Programm , und im gesamten zweiten Modul arbeiten unsere Teilnehmer mit diesem Tool. Unsere Aufgabe als Veranstalter ist es, einen Cluster fĂŒr die Verwendung in einem solchen Fall vorzubereiten.
Das Besondere an unserer Nutzung ist, dass die Anzahl der Personen, die gleichzeitig mit Spark arbeiten, gleich der gesamten Gruppe sein kann. Beispielsweise beim Seminar, wenn alle gleichzeitig etwas ausprobieren und das Nachmachen, was unser Dozent zeigt. Das sind manchmal fast 40 Personen. Wahrscheinlich gibt es nicht viele Unternehmen auf der Welt, die mit diesem Nutzungsszenario konfrontiert sind.
Im Folgenden werde ich erlÀutern, wie und warum wir bestimmte Konfigurationsparameter ausgewÀhlt haben.
Lass uns ganz von vorne beginnen. Spark hat 3 Möglichkeiten, um auf einem Cluster zu arbeiten: standalone, mit Mesos und mit YARN. Wir haben uns fĂŒr die dritte Option entschieden, weil sie fĂŒr uns logisch war. Wir haben bereits einen Hadoop-Cluster. Unsere Teilnehmer sind mit seiner Architektur gut vertraut. Lassen Sie uns YARN verwenden.
spark.master=yarnDann wird es interessanter. Jede dieser 3 Bereitstellungsoptionen hat 2 Bereitstellungsarten: client und cluster. Ausgehend von und verschiedenen Links im Internet kann man schlieĂen, dass client fĂŒr interaktive Arbeiten geeignet ist â beispielsweise ĂŒber Jupyter Notebook, wĂ€hrend cluster mehr fĂŒr Produktionslösungen geeignet ist. In unserem Fall interessierte uns die interaktive Arbeit, deshalb:
spark.deploy-mode=clientIm Allgemeinen wird Spark ab diesem Zeitpunkt bereits auf YARN funktionieren, aber das war uns nicht genug. Da wir ein Programm ĂŒber groĂe Daten haben, fehlte es den Teilnehmern manchmal an den Ressourcen, die bei einer gleichmĂ€Ăigen Verteilung zur VerfĂŒgung standen. Und hier fanden wir eine interessante Sache â die dynamische Ressourcenallokation. Kurz gesagt, der Kern ist folgender: Wenn Sie eine rechenintensive Aufgabe haben und der Cluster frei ist (zum Beispiel morgens), dann kann Spark Ihnen mit dieser Option zusĂ€tzliche Ressourcen zuteilen. Der Bedarf wird dort durch eine komplizierte Formel berechnet. Wir wollen ins Detail nicht eingehen â sie funktioniert ganz gut.
spark.dynamicAllocation.enabled=trueWir haben diesen Parameter gesetzt, und beim Starten von Spark gibt es einen Fehler und es startet nicht. Richtig, denn wir hĂ€tten lesen sollen aufmerksamer. Dort steht, dass fĂŒr alles in Ordnung ist, noch ein zusĂ€tzlicher Parameter aktiviert werden muss.
spark.shuffle.service.enabled=trueWarum ist das nötig? Wenn unser Job nicht mehr so viele Ressourcen benötigt, sollte Spark sie in den gemeinsamen Pool zurĂŒckgeben. Der zeitaufwĂ€ndigste Schritt in fast jeder MapReduce-Aufgabe ist die Shuffle-Phase. Dieser Parameter ermöglicht es, die Daten, die in dieser Phase entstehen, zu speichern und damit die Executors freizugeben. Ein Executor ist der Prozess, der auf dem Worker alles berechnet. Er hat eine bestimmte Anzahl von CPU-Kernen und einen bestimmten Speicher.
Wir haben diesen Parameter hinzugefĂŒgt. Es schien alles zu funktionieren. Es wurde deutlich, dass den Teilnehmern tatsĂ€chlich mehr Ressourcen zur VerfĂŒgung gestellt wurden, wenn sie benötigt wurden. Aber ein anderes Problem trat auf â irgendwann wachten andere Teilnehmer auf und wollten ebenfalls Spark nutzen, aber alles war besetzt und sie waren unzufrieden. Das kann man nachvollziehen. Wir begannen, in der Dokumentation nachzusehen. Dort stellte sich heraus, dass es noch eine Reihe von Parametern gibt, mit denen man den Prozess beeinflussen kann. Zum Beispiel: Wenn der Executor im Leerlauf ist â nach wie viel Zeit können wir ihm die Ressourcen entziehen?
spark.dynamicAllocation.executorIdleTimeout=120sIn unserem Fall â wenn Ihre Executors in zwei Minuten nichts tun, dann, seien Sie so freundlich, sie zurĂŒck in den allgemeinen Pool zu geben. Aber auch dieser Parameter war nicht immer ausreichend. Es war deutlich zu sehen, dass die Person schon lange nichts macht, und die Ressourcen wurden nicht freigegeben. Es stellte sich heraus, dass es noch einen speziellen Parameter gibt â nach welcher Zeit die Executors ausgewĂ€hlt werden sollen, die zwischengespeicherte Daten enthalten. StandardmĂ€Ăig war dieser Parameter â unendlich! Wir haben ihn angepasst.
spark.dynamicAllocation.cachedExecutorIdleTimeout=600sDas heiĂt, wenn Ihre Executors in den letzten 5 Minuten nichts tun, geben Sie sie zurĂŒck in den allgemeinen Pool. In diesem Modus wurde die Geschwindigkeit der Freigabe und Bereitstellung von Ressourcen fĂŒr eine groĂe Anzahl von Benutzern akzeptabel. Die Anzahl der Unzufriedenen hat abgenommen. Aber wir haben uns entschieden, weiterzugehen und die maximale Anzahl der Executors fĂŒr eine Anwendung zu begrenzen â im Grunde fĂŒr einen Teilnehmer des Programms.
spark.dynamicAllocation.maxExecutors=19Nun gab es natĂŒrlich Beschwerden von anderer Seite â âDer Cluster steht still, und ich habe nur 19 Executorsâ, aber was soll's â es braucht irgendein richtiges Gleichgewicht. Es ist nicht möglich, alle glĂŒcklich zu machen.
Und noch eine kleine Geschichte, die mit den Besonderheiten unseres Falls zusammenhĂ€ngt. Einmal kamen einige Personen zu spĂ€t zum praktischen Unterricht, und aus irgendeinem Grund startete Spark nicht. Wir haben die Anzahl der verfĂŒgbaren Ressourcen angeschaut â schien ausreichend zu sein. Spark sollte starten. GlĂŒcklicherweise hatte sich zu diesem Zeitpunkt die Dokumentation bereits irgendwo ins GedĂ€chtnis eingeprĂ€gt, und wir erinnerten uns, dass Spark beim Start einen Port sucht, auf dem es lĂ€uft. Wenn der erste Port im Bereich belegt ist, wechselt es zum nĂ€chsten. Wenn dieser frei ist, nimmt es ihn. Und es gibt einen Parameter, der die maximale Anzahl der Versuche dafĂŒr angibt. StandardmĂ€Ăig sind es 16. Das ist weniger als die Anzahl der Personen in unserer Gruppe beim Unterricht. Folglich brach Spark nach 16 Versuchen ab und sagte, dass es nicht starten könnte. Wir haben diesen Parameter angepasst.
spark.port.maxRetries=50Ich werde nun ĂŒber einige Einstellungen sprechen, die nicht mehr stark mit den Besonderheiten unseres Falls verbunden sind.
Um Spark schneller zu starten, gibt es die Empfehlung, den Jar-Ordner, der im Stammverzeichnis von SPARK_HOME liegt, zu archivieren und auf HDFS zu legen. Dadurch wird die Zeit fĂŒr das Laden dieser JARs auf den Workern eingespart.
spark.yarn.archive=hdfs:///tmp/spark-archive.zipUm die Leistung zu verbessern, wird empfohlen, als Serialisierer Kryo zu verwenden. Es ist optimierter als der Standardserialisierer.
spark.serializer=org.apache.spark.serializer.KryoSerializerEin weiteres bekanntes Problem mit Spark ist, dass es hĂ€ufig aufgrund von Speichermangel abstĂŒrzt. Dies geschieht oft, wenn die Worker alle Berechnungen abgeschlossen haben und das Ergebnis an den Driver senden. Wir haben diesen Parameter erhöht. StandardmĂ€Ăig betrĂ€gt er 1 GB, wir haben ihn auf 3 GB erhöht.
spark.driver.maxResultSize=3072Und schlieĂlich, als Bonus. Wie man Spark auf Version 2.1 im HortonWorks-Distro â HDP 2.5.3.0 â aktualisiert. Diese HDP-Version enthĂ€lt eine vorinstallierte Version 2.0, aber wir haben irgendwann entschieden, dass sich Spark ziemlich aktiv weiterentwickelt, und jede neue Version behebt Bugs und bietet zusĂ€tzliche Funktionen, auch fĂŒr die Python-API. Daher haben wir uns entschlossen, das Update durchzufĂŒhren.
Wir haben die Version von der offiziellen Website fĂŒr Hadoop 2.7 heruntergeladen. Wir haben sie entpackt und in den HDP-Ordner verschoben. Wir haben die Symlinks wie gewĂŒnscht erstellt. Wir starten â es funktioniert nicht. Es gibt eine sehr unklare Fehlermeldung.
java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfigNach einer Google-Suche stellten wir fest, dass Spark beschlossen hat, nicht zu warten, bis Hadoop eine neue Version bereitstellt, und eine neue Version von Jersey verwenden wollte. Sie streiten sich darĂŒber in JIRA. Die Lösung war â herunterzuladen . Dieses in den jars-Ordner von SPARK_HOME verschieben, wieder zippen und auf HDFS hochladen.
Wir haben diesen Fehler umgangen, aber ein neuer und recht vager trat auf.
org.apache.spark.SparkException: Yarn-Anwendung ist bereits beendet! Sie wurde möglicherweise beendet oder konnte den Anwendungshauptprozess nicht starten.Wir versuchen dabei, Version 2.0 zu starten - alles in Ordnung. Versuche zu erraten, woran es liegt. Wir haben die Protokolle dieser Anwendung eingesehen und Folgendes gesehen:
/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jarIm Allgemeinen wurde aus irgendeinem Grund hdp.version nicht aufgelöst. Nach einer Google-Suche fanden wir die Lösung. Man muss in Ambari zu den YARN-Einstellungen gehen und dort einen Parameter im benutzerdefinierten yarn-site hinzufĂŒgen:
hdp.version=2.5.3.0-37Diese Magie half, und Spark startete. Wir haben einige unserer Jupyter-Notebooks getestet. Alles funktioniert. FĂŒr die erste Unterrichtsstunde zu Spark am Samstag (schon morgen) sind wir bereit!
UPD. WĂ€hrend des Unterrichts stellte sich ein weiteres Problem heraus. Irgendwann hörte YARN auf, Container fĂŒr Spark auszugeben. In YARN musste der Parameter geĂ€ndert werden, der standardmĂ€Ăig auf 0,2 eingestellt war:
yarn.scheduler.capacity.maximum-am-resource-percent=0.8 Das heiĂt, nur 20 % der Ressourcen waren an der Ressourcenverteilung beteiligt. Nach Anpassung der Parameter haben wir YARN neu geladen. Das Problem wurde gelöst, und auch die anderen Teilnehmer konnten den Spark-Kontext starten.
Quelle: habr.com
