Habr, üdvözlet! Tegnap a , 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 , é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=yarnA 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 é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=clientAlapvető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=trueBeállítottuk ezt a paramétert, és amikor elindítottuk a Sparkot, az figyelmeztetett és nem indult el. Jogos, mert figyelmesebben kellett volna olvasni. Ott szerepel, hogy ahhoz, hogy minden rendben legyen, egy másik paramétert is be kell kapcsolni.
spark.shuffle.service.enabled=trueMire 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=120sA 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=600sTehá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=19Most, 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=50Most 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.zipA 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.KryoSerializerEgy 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=3072Vé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/ClientConfigGoogle 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 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-37Ez 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
