Habr, hallo! Gisteren op , hadden de jongens van Rambler&Co behoorlijk wat vragen van deelnemers over het configureren van deze tool. We besloten om na afloop onze ervaringen te delen. Het onderwerp is niet eenvoudig — daarom moedigen we ook aan om ervaringen in de reacties te delen; misschien begrijpen en gebruiken wij ook iets verkeerd.
Een korte inleiding — hoe wij Spark gebruiken. We hebben een drie maanden durend programma , en in de tweede module werken onze deelnemers met deze tool. Onze taak als organisatoren is dan ook om een cluster voor gebruik in dit geval voor te bereiden.
Een bijzonderheid van ons gebruik is dat het aantal mensen dat tegelijkertijd met Spark werkt gelijk kan zijn aan de hele groep. Bijvoorbeeld, tijdens een seminar, wanneer iedereen tegelijkertijd iets probeert en herhaalt wat onze docent zegt. Soms zijn dat wel 40 personen. Er zijn waarschijnlijk niet veel bedrijven ter wereld die met zo'n gebruiksscenario te maken krijgen.
Hierna vertel ik hoe en waarom we bepaalde configuratieparameters hebben gekozen.
Laten we beginnen bij het begin. Spark heeft 3 manieren om op een cluster te werken: standalone, met Mesos en met YARN. We besloten de derde optie te kiezen, omdat deze voor ons logisch was. We hebben al een Hadoop-cluster. Onze deelnemers zijn al goed bekend met de architectuur ervan. Laten we YARN gebruiken.
spark.master=yarnDan wordt het interessanter. Elk van deze 3 uitrolopties heeft 2 opties voor de implementatie: client en cluster. Gebaseerd op en verschillende links op internet, kan worden geconcludeerd dat client geschikt is voor interactieve werkzaamheden — bijvoorbeeld via Jupyter Notebook, terwijl de cluster meer geschikt is voor productieoplossingen. In ons geval was interactieve samenwerking het meest interessant, daarom:
spark.deploy-mode=clientIn feite zou Spark vanaf dit moment al op YARN kunnen werken, maar dat was niet genoeg voor ons. Aangezien ons programma zich richt op big data, ontbrak het soms aan wat er werd verkregen met een gelijkmatige verdeling van middelen. En hier vonden we iets interessants — dynamische toewijzing van middelen. Kort gezegd: als je een zware taak hebt en het cluster vrij is (bijvoorbeeld 's ochtends), kan Spark je via deze optie extra middelen geven. De noodzaak wordt daar berekend volgens een slimme formule. We gaan hier niet te veel op in — het werkt redelijk goed.
spark.dynamicAllocation.enabled=trueWe hebben deze parameter ingesteld, en bij het opstarten van Spark gaf het een foutmelding en startte het niet op. Dat is juist, want we hadden de nauwkeuriger moeten lezen. Daarin staat dat om alles goed te laten verlopen, er nog een extra parameter moet worden ingeschakeld.
spark.shuffle.service.enabled=trueWat is het nut ervan? Wanneer onze job niet meer zoveel middelen vereist, moet Spark deze teruggeven aan de algemene pool. De meest tijdrovende fase in bijna elke MapReduce-taak is de Shuffle-fase. Deze parameter stelt ons in staat gegevens te behouden die in deze fase ontstaan en vrij te geven executors. Een executor is een proces dat alles op de worker berekent. Het heeft een bepaalde hoeveelheid CPU-kernen en een bepaalde hoeveelheid geheugen.
We hebben deze parameter toegevoegd. Het leek allemaal goed te werken. Het was duidelijk dat deelnemers daadwerkelijk meer middelen kregen wanneer ze dat nodig hadden. Maar er ontstond een ander probleem — op een gegeven moment kwamen andere deelnemers weer in actie en wilden ook Spark gebruiken, maar alles was bezet, en ze waren niet tevreden. We kunnen ze begrijpen. We gingen de documentatie bekijken. Daar bleek dat er nog meerdere parameters zijn waarmee we invloed kunnen uitoefenen op het proces. Bijvoorbeeld, als een executor in de wachtstand staat — na hoeveel tijd kunnen we de middelen terugtrekken?
spark.dynamicAllocation.executorIdleTimeout=120sIn ons geval: als uw executors gedurende twee minuten niets doen, geef ze dan terug aan de algemene pool. Maar zelfs deze parameter was niet altijd voldoende. Het was duidelijk dat iemand al een lange tijd niets deed, maar de middelen werden niet vrijgegeven. Het bleek dat er nog een speciale parameter was — na hoeveel tijd executors die gecachte gegevens bevatten, moeten worden teruggenomen. Standaard stond deze parameter op — infinity! We hebben dit aangepast.
spark.dynamicAllocation.cachedExecutorIdleTimeout=600sDus als uw executors gedurende 5 minuten niets doen, geef ze dan terug aan de algemene pool. In deze modus werd de snelheid van het vrijgeven en toewijzen van middelen voor een groot aantal gebruikers acceptabel. Het aantal klachten nam af. Maar we hebben besloten verder te gaan en het maximale aantal executors per applicatie te beperken — in wezen per deelnemer aan het programma.
spark.dynamicAllocation.maxExecutors=19Nu zijn er natuurlijk ontevreden mensen aan de andere kant — “het cluster staat stil, en ik heb maar 19 executors”, maar wat kun je eraan doen — er moet een goede balans zijn. Iedereen tevreden stellen is niet mogelijk.
En nog een klein verhaal met betrekking tot de specifics van onze casus. Een paar mensen kwamen te laat naar de praktische les, en om de een of andere reden startte hun Spark niet. We keken naar het aantal beschikbare middelen — het leek genoeg. Spark zou moeten starten. Gelukkig was de documentatie inmiddels ergens in ons hoofd opgeslagen, en we herinnerden ons dat wanneer je Spark start, het een poort zoekt om te beginnen. Als de eerste poort in het bereik bezet is, gaat het naar de volgende. Als deze vrij is, neemt het die in gebruik. En er is een parameter die het maximale aantal pogingen hiervoor aangeeft. Standaard is dit 16. Dit getal is minder dan het aantal mensen in onze groep tijdens de les. Daarom gooide Spark de handdoek in de ring na 16 pogingen en zei dat het niet kon starten. We hebben deze parameter aangepast.
spark.port.maxRetries=50Daarna zal ik enkele instellingen bespreken die minder sterk verbonden zijn met de specifics van onze casus.
Voor een snellere start van Spark is het aan te raden de jars-map, die zich in de thuisdirectory SPARK_HOME bevindt, te archiveren en op HDFS te plaatsen. Hierdoor zal hij geen tijd verspillen aan het laden van deze jars op de workers.
spark.yarn.archive=hdfs:///tmp/spark-archive.zipVoor een snellere werking wordt aanbevolen om Kryo als serializer te gebruiken. Het is beter geoptimaliseerd dan de standaardoptie.
spark.serializer=org.apache.spark.serializer.KryoSerializerEr is een langdurig probleem met Spark dat het vaak crashes door geheugenproblemen. Dit gebeurt vaak op het moment dat de workers alles hebben berekend en de resultaten naar de driver sturen. We hebben deze parameter vergroot. Standaard is het 1GB, wij hebben het op 3 ingesteld.
spark.driver.maxResultSize=3072Als laatste, hoe Spark te upgraden naar versie 2.1 op de HortonWorks-distributie - HDP 2.5.3.0. Deze versie van HDP bevat een voorgeïnstalleerde versie 2.0, maar we hebben ooit besloten dat Spark zich vrij actief ontwikkelt, en elke nieuwe versie verhelpt bugfixes en biedt extra mogelijkheden, ook voor de Python API. Daarom hebben we besloten om een update uit te voeren.
We hebben de versie van de officiële website voor Hadoop 2.7 gedownload. We hebben het uitgepakt, in de HDP-map geplaatst en de symlinks gemaakt zoals het hoort. We starten het op, maar het wil niet opstarten. Er verschijnt een onduidelijke foutmelding.
java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfigNa een Google-zoekactie ontdekten we dat Spark ervoor heeft gekozen om niet te wachten totdat Hadoop klaar is, en besloten om een nieuwe versie van Jersey te gebruiken. Ze hebben zelf ruzie hierover in JIRA. De oplossing was - download . Plaats dit in de jars-map in SPARK_HOME, maak opnieuw een zip en upload deze naar HDFS.
We hebben deze fout omzeild, maar er ontstond een nieuwe en behoorlijk onduidelijke.
org.apache.spark.SparkException: Yarn-toepassing is al beëindigd! Het kan zijn dat het is beëindigd of dat het moeilijk was om de toepassingsmaster te starten.Bij het proberen om versie 2.0 op te starten - alles werkt goed. Probeer maar te raden wat het probleem is. We hebben in de logs van deze applicatie gekeken en iets als volgt gezien:
/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jarOver het algemeen kon hdp.version om de een of andere reden niet worden opgelost. Na een Google-zoekactie vonden we een oplossing. We moesten naar de YARN-instellingen in Ambari gaan en daar een parameter aan de aangepaste yarn-site toevoegen:
hdp.version=2.5.3.0-37Deze magie hielp, en Spark ging van start. We hebben een aantal van onze Jupyter-notebooks getest. Alles werkt. We zijn klaar voor de eerste les over Spark op zaterdag (al morgen)!
UPD. Tijdens de les bleek er nog een probleem. Op een gegeven moment gaf YARN geen containers meer voor Spark. In YARN moest een parameter worden aangepast, die standaard op 0.2 stond:
yarn.scheduler.capacity.maximum-am-resource-percent=0.8 Dat wil zeggen dat slechts 20% van de middelen betrokken was bij de toewijzing van hulpbronnen. Door de parameters te wijzigen, herstarten we YARN. Het probleem was opgelost en de andere deelnemers konden ook de Spark-context starten.
Bron: habr.com
