Spark konfigurálása YARN alatt

Habr, üdvözlet! Tegnap a Apache Spark-ról szóló meetupon, a Rambler&Co csapatától, elég sok kérdés merült fel a résztvevők részéről a konfigurálásával kapcsolatban. Úgy döntöttünk, hogy a nyomában megosztjuk saját tapasztalatainkat. A téma nem egyszerű — ezért azt javasoljuk, hogy a kommentekben is osszuk meg tapasztalatainkat, lehet, hogy mi is valamit félreértelmeztünk vagy rosszul használunk.

Egy kis bevezetés — hogyan használjuk a Spark-ot. Van egy három hónapos programunk „Nagy adatok szakértője”, és a második modulban a résztvevők ezen az eszközön dolgoznak. Így tehát a mi feladatunk, mint szervezők, hogy felkészítsünk egy klasztert az ilyen esetek használatára.

A használatunk sajátossága, hogy az Spark-ot egy időben a teljes csoport használja. Például egy workshop során, amikor mindenki egyszerre próbál valamit és a tanárunk nyomán ismétli. Ez pedig nem kis szám — néha 40 főt is elérhet. Valószínűleg nem sok olyan cég van a világon, amely hasonló felhasználási forgatókönyvvel találkozik.

Ezután elmondom, hogyan és miért választottuk ki a különböző konfigurációs paramétereket.

Kezdjük a legelejétől. A Spark-nak 3 módja van a klaszteren való működésre: standalone, Mesos használatával és YARN használatával. Mi a harmadik lehetőséget választottuk, mert számunkra logikus volt. Már van egy Hadoop klaszterünk. A résztvevők már jól ismerik annak architektúráját. Használjuk a YARN-t.

spark.master=yarn

A folytatás még érdekesebb. Mindhárom telepítési mód esetén 2 telepítési lehetőség áll rendelkezésre: client és cluster. A dokumentáció és különböző internetes források alapján azt lehet mondani, hogy a client az interaktív munkához alkalmas — például jupyter notebook-on keresztül, míg a cluster inkább a production megoldásokhoz illik. Az esetünkben minket az interaktív munka érdekelt, ezért:

spark.deploy-mode=client

Alapvetően ettől a pillanattól kezdve a Spark már valamilyen módon működni fog a YARN-on, de nekünk ez nem volt elég. Mivel a programunk a nagy adatokkal foglalkozik, néha a résztvevőknek hiányzott az, ami a források egyenletes elosztásából adódott. És itt találtunk egy érdekes dolgot — a dinamikus forrásallokációt. Röviden: ha nehéz feladatot végzel és a klaszter szabad (például reggel), akkor ezzel az opcióval a Spark további forrásokat adhat neked. A szükségletet egy ügyes képlettel számolják ki. A részletekbe nem megyünk bele — ez jól működik.

spark.dynamicAllocation.enabled=true

Beállítottuk ezt a paramétert, és amikor elindítottuk a Sparkot, az figyelmeztetett és nem indult el. Jogos, mert figyelmesebben kellett volna olvasni. a dokumentációval Ott szerepel, hogy ahhoz, hogy minden rendben legyen, egy másik paramétert is be kell kapcsolni.

spark.shuffle.service.enabled=true

Mire van szükség? Amikor a munkánk már nem igényel annyi forrást, a Sparknak vissza kell adnia azokat a közös poolba. A legmunkaigényesebb fázis szinte bármely MapReduce feladatban a Shuffle fázis. Ez a paraméter lehetővé teszi az ezen a fázison keletkezett adatok megőrzését, és így felszabadítja az executoreket. Az executor az a folyamat, amely a munkán mindent kiszámít. Van valamennyi processzormagja és valamilyen mennyiségű memóriája.

Hozzáadtuk ezt a paramétert. Minden rendben működött. Észrevettük, hogy a résztvevők valóban több forrást kaptak, amikor szükségük volt rá. De felmerült egy másik probléma — egy adott pillanatban más résztvevők is felébredtek, és ők is használni akarták a Sparkot, de minden foglalt volt, és ők nem voltak elégedettek. Megérthetjük őket. Elkezdtek nézni a dokumentációt. Kiderült, hogy van még néhány paraméter, amellyel befolyásolhatjuk a folyamatot. Például, ha az executor várakozó üzemmódban van — mennyi idő múlva lehet elvenni tőle a forrásokat?

spark.dynamicAllocation.executorIdleTimeout=120s

A mi esetünkben, ha az executoraid két percig nem végeznek semmit, kérlek, tedd őket vissza a közös poolba. De ez a paraméter sem mindig volt elegendő. Látható volt, hogy valaki már régóta nem csinál semmit, de az erőforrások nem szabadultak fel. Kiderült, hogy van egy külön paraméter is — mennyi idő elteltével kell szűrni az executoraidat, amelyek gyorsítótárazott adatokat tartalmaznak. Alapértelmezés szerint ez a paraméter infinity értéken állt! Ezt módosítottuk.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

Tehát, ha az executoraid 5 percig nem végeznek semmit, add át őket a közös poolnak. Ezzel a módszerrel az erőforrások felszabadítási és kiadási sebessége a sok felhasználó számára megfelelő lett. A panaszok száma csökkent. De úgy döntöttünk, tovább lépünk, és korlátozzuk az alkalmazásonkénti maximális executorszámot — lényegében egy program résztvevőre.

spark.dynamicAllocation.maxExecutors=19

Most, természetesen, másik oldalról is érkeztek panaszok — "a klaszter tétlen, de nekem csak 19 executorom van", de mit tegyünk — szükség van valamilyen helyes egyensúlyra. Mindenkit boldoggá tenni nem lehet.

És még egy kis történet, amely a mi esetünkhöz kapcsolódik. Egyszer néhány ember késve érkezett a gyakorlati órára, és valamiért a Spark nem indult el náluk. Megnéztük a szabad erőforrások számát — úgy tűnik, van. A Sparknak el kellett volna indulnia. Szerencsére arra az időre a dokumentáció már valahol beépült az emlékezetünkbe, és eszünkbe jutott, hogy a Spark indításakor portot keres, amelyen elindulhat. Ha az első port az intervallumban foglalt, átlép a következőre. Ha az szabad, akkor megkapja. Van egy paraméter, amely meghatározza a maximális próbálkozások számát. Alapértelmezés szerint ez 16. Kevesebb, mint ahány ember van a csoportunkban az órán. Ennek megfelelően, 16 próbálkozás után a Spark feladta és azt mondta, hogy nem tud elindulni. Ezt a paramétert módosítottuk.

spark.port.maxRetries=50

Most néhány beállítást fogok megosztani, amelyek már nem nagyon kapcsolódnak a mi esetünkhöz.

A Spark gyorsabb indításához javasolják, hogy a SPARK_HOME otthoni könyvtárában lévő jars mappát archíváljuk és helyezzük el az HDFS-en. Így nem fog időt pazarolni ezeknek a jar fájloknak a munkásokhoz való betöltésére.

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

A gyorsabb működés érdekében javasolt a kryo használata mint sorosító. Ez optimalizáltabb, mint az alapértelmezett.

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

Egy régi probléma a Sparkkal, hogy gyakran memóriahibát okoz. Gyakran ez akkor történik, amikor a munkások már mindent kiszámoltak és küldik az eredményt a vezérlőhöz. Mi ezt a paramétert megnöveltük. Alapértelmezés szerint 1GB, mi 3-ra állítottuk.

spark.driver.maxResultSize=3072

Végül, mint desszert. Hogyan frissítsük a Sparkot 2.1-es verzióra a HortonWorks disztribúcióján — HDP 2.5.3.0. Ez a HDP verzió előre telepített 2.0-ás verziót tartalmaz, de egyszer úgy döntöttünk, hogy a Spark eléggé aktívan fejlődik, és minden új verzió javít valamilyen hibát, plusz új lehetőségeket ad, beleértve a Python API-t is, ezért úgy döntöttünk, hogy frissítjük.

Letöltöttük a Hadoop 2.7-hez készült verziót az hivatalos oldalról. Kicsomagoltuk, beletettük a HDP mappájába. Beállítottuk a szimbolikus linkeket, ahogy kell. Elindítjuk — nem indul. Nagyon érthetetlen hibát ír.

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

Google keresés után kiderült, hogy a Spark nem akarta megvárni, amíg a Hadoop elkészül, és úgy döntött, hogy új jersey verziót használ. Ezen díleket vitatják a JIRA-n. A megoldás az volt, hogy letöltjük jersey 1.17.1 verzióját.Beletettük ezt a SPARK_HOME jars mappájába, újra zipeltük és feltettük az HDFS-re.

Ezt a hibát megoldottuk, de egy új, meglehetősen zavaros hiba merült fel.

org.apache.spark.SparkException: Yarn application has already ended! Lehet, hogy megölték, vagy nem tudta elindítani az alkalmazás főprogramját.

Ekkor megpróbáltuk elindítani a 2.0-ás verziót — minden rendben van. Próbáld kitalálni, mi a probléma. Beleléptünk az alkalmazás logjaiba és valami ilyet láttunk:

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

Összességében valamilyen oknál fogva a hdp.version nem volt feloldva. Google keresés után megtaláltuk a megoldást. Az Ambari-ban be kell lépni a YARN beállításokba, és hozzá kell adni egy paramétert a testreszabott yarn-site-hoz:

hdp.version=2.5.3.0-37

Ez a varázslat segített, és a Spark működésbe lépett. Teszteltük néhány jupyter-notebookunkat. Minden működik. Készen állunk az első Spark órára szombaton (már holnap)!

UPD. Az órán egy újabb probléma merült fel. Egy bizonyos pillanatban a YARN megállt, hogy konténereket adjon a Sparknak. A YARN-ban javítani kellett egy paramétert, amely alapértelmezés szerint 0.2 volt:

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

Tehát csak a források 20%-a vett részt az erőforrások kiosztásában. A paraméterek módosítása után újraindítottuk a YARN-t. A probléma megoldódott, és a többi résztvevő is el tudta indítani a spark kontextust.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster