Habr, pozdrav! Jučer na , od ekipe iz Rambler&Co, bilo je dosta pitanja od učesnika u vezi sa konfiguracijom ovog alata. Odlučili smo da podelimo svoje iskustvo. Tema nije jednostavna — zato pozivamo i vas da podelite svoje iskustvo u komentarima, možda i mi nešto ne razumemo i koristimo pogrešno.
Kratka uvodna rečenica — kako mi koristimo Spark. Imamo tromesečni program , a u drugom modulu naši učesnici rade s ovim alatom. Naša zadatak, kao organizatora, je da pripremimo klaster za korišćenje u ovom slučaju.
Posebnost našeg korišćenja je u tome što broj ljudi koji istovremeno rade na Sparku može biti jednak celoj grupi. Na primer, na seminaru kada svi istovremeno nešto probaju i ponavljaju za našim predavačem. A to nije malo — ponekad i do 40 ljudi. Verovatno nije mnogo kompanija u svetu koje se suočavaju s takvim scenarijem korišćenja.
Dalje ću objasniti kako i zašto smo birali određene parametre konfiguracije.
Počnimo od samog početka. Spark ima 3 načina rada na klasteru: standalone, koristeći Mesos i koristeći YARN. Odlučili smo se za treću opciju, jer nam je bila logična. Već imamo hadoop-klaster. Naši učesnici su dobro upoznati s njegovom arhitekturom. Hajde da koristimo YARN.
spark.master=yarnDalje je zanimljivije. Svaka od ovih 3 opcija instalacije ima 2 načina implementacije: client i cluster. Na osnovu i raznih linkova na internetu, može se zaključiti da je client pogodan za interaktivni rad — na primer, preko jupyter notebook-a, dok je cluster više odgovarajući za produkciona rešenja. U našem slučaju nas je zanimao interaktivni rad, stoga:
spark.deploy-mode=clientNa splošno bo od tega trenutka Spark nekako deloval na YARN, a to nam ni bilo dovolj. Ker imamo program o velikih podatkih, je včasih udeležencem primanjkovalo tistega, kar je bilo doseženo v okviru enotnega razreza virov. In tukaj smo našli zanimivo stvar — dinamično dodeljevanje virov. Na kratko, bistvo je naslednje: če imate težko nalogo in je grozd prost (na primer zjutraj), vam lahko Spark s to možnostjo poda dodatne vire. Potreba se šteje po zapleteni formuli. Ne bomo šli v podrobnosti — deluje precej dobro.
spark.dynamicAllocation.enabled=trueNastavili smo ta parameter, in ob zagonu je Spark opozoril in se ni zagnal. In prav je tako, ker je bilo treba prebrati bolj pozorno. Tam je navedeno, da je za vse, da bo v redu, treba vključiti še en dodaten parameter.
spark.shuffle.service.enabled=trueZakaj je potreben? Ko naš projekt ne zahteva več toliko virov, jih mora Spark vrniti v skupni rezervoar. Najbolj delovno intenzivna faza v skoraj vsakem MapReduce projektu je faza Shuffle. Ta parameter omogoča shranjevanje podatkov, ki nastanejo v tej fazi, in s tem sprosti executors. Executor je proces, ki na delavcu vse izračuna. Ima določeno število procesorskih jeder in določeno količino pomnilnika.
Dodali smo ta parameter. Vse se je zdelo, da deluje. Opazno je bilo, da so udeleženci dejansko dobivali več virov, ko so jih potrebovali. A pojavila se je druga težava — v nekem trenutku so se drugi udeleženci zbudili in prav tako želeli uporabljati Spark, vendar je bilo vse zasedeno, kar jih je razburilo. Njih lahko razumemo. Začeli smo preverjati dokumentacijo. Izkazalo se je, da obstaja še nekaj parametrov, s katerimi lahko vplivamo na postopek. Na primer, če je executor v načinu pričakovanja — po koliko času lahko vzamemo vire?
spark.dynamicAllocation.executorIdleTimeout=120sV našem případě — pokud vaši executors nic nedělají po dobu dvou minut, vraťte je prosím do společného poolu. Ale ani tento parametr nebyl vždy dostačující. Bylo jasné, že člověk už dlouho nic nedělá, a prostředky se neuvolňují. Ukázalo se, že existuje ještě speciální parametr — po jaké době odstraňovat executors, kteří obsahují vyrovnaná data. Standardně byl tento parametr nastaven na — nekonečno! Opraveno.
spark.dynamicAllocation.cachedExecutorIdleTimeout=600sTo znamená, že pokud vaše executors nic nedělají po dobu 5 minut, vraťte je do společného poolu. V takovém režimu se rychlost uvolňování a poskytování zdrojů pro velké množství uživatelů zlepšila. Počet nespokojených se snížil. Ale rozhodli jsme se jít dále a omezit maximální počet executors na jednu aplikaci — v podstatě na jednoho účastníka programu.
spark.dynamicAllocation.maxExecutors=19Nyní se samozřejmě objevily nespokojenosti z druhé strany — "klastr nepracuje a mám pouze 19 executors", ale co se dá dělat — je potřeba najít správnou rovnováhu. Není možné udělat všechny šťastné.
A ještě jeden malý příběh související se specifiky našeho případu. Někdo přišel na praktickou hodinu pozdě, a jejich Spark z nějakého důvodu nenastartoval. Podívali jsme se na množství volných prostředků — zdálo se, že jsou. Spark by měl startovat. Naštěstí, do té doby se nám už dokumentace zapsala do paměti, a vzpomněli jsme si, že při spuštění Spark hledá port, na kterém se má spustit. Pokud je první port v rozsahu obsazen, přechází na další v pořadí. Pokud je volný, zabere ho. A existuje parametr, který ukazuje maximální počet pokusů pro to. Standardně — to je 16. Číslo menší než počet lidí v naší skupině na lekci. Tudíž po 16 pokusech Spark to vzdal a řekl, že nemohu nastartovat. Opraveno.
spark.port.maxRetries=50Dále povím o některých nastaveních, které už nejsou příliš spojeny se specifiky našeho případu.
Pro rychlejší start Spark existuje doporučení zabalit složku jars z domovského adresáře SPARK_HOME a umístit ji na HDFS. Poté nebude ztrácet čas načítáním těchto jarů na workery.
spark.yarn.archive=hdfs:///tmp/spark-archive.zipPriporočamo uporabo kryo kot serializer za bolj hitro delovanje. Je bolj optimiziran od privzetega.
spark.serializer=org.apache.spark.serializer.KryoSerializerObstaja tudi dolgoletna težava pri Sparku, da pogosto pade zaradi pomnilnika. To se pogosto zgodi, ko so delavci vse izračunali in pošiljajo rezultate na vozniški računalnik. Mi smo ta parameter povečali. Privzeto je 1 GB, mi smo ga nastavili na 3.
spark.driver.maxResultSize=3072In zadnje, kako posodobiti Spark na različico 2.1 na distribuciji HortonWorks – HDP 2.5.3.0. Ta različica HDP vsebuje prednameščeno različico 2.0, toda nekega dne smo se odločili, da se Spark aktivno razvija in vsaka nova različica odpravlja napake ter ponuja nove možnosti, tudi za python API, zato smo se odločili, da naredimo posodobitev.
Prenesli smo različico s uradne spletne strani za Hadoop 2.7. Jo razpakirali, prenesli v mapo s HDP. Ustvarili smo povezave, kot je treba. Začnemo – ne zažene se. Prikazuje zelo nejasno napako.
java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfigPo iskanju po Googlu smo ugotovili, da Spark ne čaka, da se Hadoop dokonča, in se odločil uporabiti novo različico jersey. O tem se med seboj prepirajo v JIRA. Rešitev je bila – prenesti . To smo dali v mapo jars v SPARK_HOME, spet naredili zip in prenesli na HDFS.
To napako smo obšli, a pojavila se je nova, precej nejasna.
org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application masterPri tem poskušamo zagnati različico 2.0 – vse deluje. Poskusi ugotoviti, kje je težava. Poglobljeno smo pregledali dnevnike te aplikacije in videli nekaj takega:
/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jarNa splošno se iz nekega razloga hdp.version ni razrešila. Po iskanju smo našli rešitev. V Ambari je treba v nastavitvah YARN dodati parameter v prilagojen yarn-site:
hdp.version=2.5.3.0-37Ta magija je pomagala in Spark je vzletel. Testirali smo nekaj naših jupyter notebookov. Vse deluje. Na prvo predavanje o Sparku v soboto (že jutri) smo pripravljeni!
UPD. Na predavanju se je pokazala še ena težava. V nekem trenutku YARN ni več dodeljeval kontejnerjev za Spark. Treba je bilo popraviti parameter v YARN, ki je bil privzeto nastavljen na 0.2:
yarn.scheduler.capacity.maximum-am-resource-percent=0.8 To je pomenilo, da je le 20 % virov sodelovalo pri dodeljevanju virov. Po spremembi nastavitev smo ponovno zagnali YARN. Težava je bila rešena, in ostali udeleženci so prav tako lahko zagnali Spark kontekst.
Izvor: habr.com
