Annyi kihasználatlan PC van a lakásomban, hogy akár Hadoopot is telepíthetek rájuk. De egy Hadoop önmagában nem sok mindenre jó (azon kívül, hogy a családot ne csak egy, hanem három gép folyamatos zúgásával idegesítsem), ezért úgy gondoltam, kipróbálom a Sparkot.
Korábban már volt egy ilyen fellángolásom, de ott csak egy gépre akartam mindent felrakni. Mostani próbálkozásom alkalmával mindent binárisból telepítettem, hogy az időm nagy részét ne a fordítás vegye el, hanem a konfigurálás. Az egyszerűség kedvéért minden számítógépen ugyan azzal az elérési úttal helyeztem el a programokat, hogy csak egy Hadoop konfigurációt kelljen beállítani, és azt másolhassam a többi gépre.
Ez nem teljesen sikerült, mert a CentOS-es gépen a Java csomag verziószáma egy ici-picit eltér az Ubuntus gépeken lévőtől, ami a rendszerfrissítéssel is változik, de ettől az apróságtól eltekintve a konfiguráció hordozható volt.
Ezután minden gépnek meg kellett adni, hogy az összes többi gépet ugyan olyan néven lássa, tehát az /etc/hosts fájt is legyen ugyan az mindegyik vason. Ha nem így van, akkor olyan furcsa anomáliák lesznek, hogy a master gép látja a worker node-okat, de azok nem tudnak visszaszólni a master-nek. Még annyit csináltam, hogy az otthoni routert is beállítottam, hogy a Hadoopos gépeknek mindig fix IP-t adjon.
A felhasználó név is legyen ugyan az mindegyik gépen és ssh kulcsos hitelesítést kell beállítani. Mivel ez egy otthoni teszt környezet, a biztonságra nem helyeztem külön hangsúlyt, tehát nincs szeparált hadoop user, valamint a master gép egyben worker is volt.
Ezután a master gépen, ha elindítom a start-all.sh parancsot, akkor minden szükséges komponens elindul az összes gépen.
Ezután jön a Spark telepítése, szintén binárisból. Itt is ugyan az az elv érvényesül, mint a Hadoop esetén. Az összes gépre telepíteni kell. A konfigurációs állományok viszont alapból nem aktívak, mindegyik egy .template kiterjesztést kap, amit el kell távolítani, ha használni akarjuk. A slaves fájlba fel kell venni az összes gépet, amelyeket be akarunk fogni a munkába. Itt is az sbin könyvtárban van egy start-all.sh, amivel minden gépen elindíthatjuk a Sparkot.
A Spark egy táblázatos adatok feldolgozását segítő rendszer. Gyorsaságát az adja, hogy amit lehet, memóriában végez, de a műveleteket el tudja osztani több gép között is, ha kell. A Spark ezen felül lusta kiértékelést végez, ami azt jelenti, hogy addig nem hajtja végre a feladatot, amíg nem szükséges. (Ami azért érdekes, mert a való életben ezt az attitűdöt nem a gyorsasággal azonosítják.) Többféle nyelven is lehet használni a rendszert, én a Pythont választottam.
Először egy könnyed bemelegítéssel kezdtem, végigcsináltam ezt a tutorialt. Erről nem érdemes többet írni, hacsak azt nem, hogy az adatok betöltése elsőre nekem nem sikerült, mert én helyi adatot akartam betölteni, de a PySpark a HDFS-en kereste a fájlt, mikor erre rájöttem, és elhelyeztem a fájlokat a Hadoop fájlrendszerére, már könnyű volt a munka.
A próba adat elég kicsi volt. igazából a Spark a master node-on megoldott mindent. Kíváncsi voltam, meg tudom-e izzasztani a rendszert. Az egyik munkahelyi projekthez egy 19GB-os táblázatot kellett készítettem ebből az adatbázisból, gondoltam megetetem az otthoni rendszerrel. Ez már elég nagy, hogy a master ne tudja a teljes adatszettet memóriába tárolni.
Amikor elkezdtem felmásolni az adatokat HDFS-re, rögtön kaptam egy hibaüzenetet, hogy az egyik datanode-ra nem fog másolni, mert nincs rajta elég hely. Kár, mert az volt a legerősebb gép a csapatban. (Persze, ez is a CentOS-es gép volt, ahol a home kapja a legnagyobb partíciót, az összes többi adat meg pár száz gigán tömörül. Végül a HDFS adatoknak egy symlinket hoztam létre, ami a home-ra mutatott.) Az adatokról annyit érdemes tudni, hogy peak információk vannak benne pár ezer Chip-seq kísérletből.
./hdfs dfs -put ~/peaksfromchipseq.tsv /peak.tsv
Ezután indítottam a PySparkot, és betöltöttem az adatokat.
import pyspark
from pyspark.sql import SQLContext
from pyspark import SparkFiles
sql = SQLContext(sc)
peak = sql.read.option("delimiter", "\t").csv("/peak.tsv", header = True, inferSchema = True)
Ezen már elszüttyögött.
peak.filter(peak.antibody == "CTCF").groupBy("expID").count().show()
De ez is csak egy gépen futott. Úgy látszik a rendszer elég jól bírja a gyűrődést. Úgy gondoltam, itt az ideje, hogy tényleg megizzasszam a rendszert.
A következő fájl még nagyobb volt. Tíz teljes genome szekvenálásból szedtem ki a lefedettség értékeket (samtools depth), ami elérte a 143 GB-ot. Ebből akartam átlagos lefedettségeket számolni, ami egy szálon egy erősebb szerveren 3 órát vett igénybe (saját Python kód, nuku optimalizáció, azért tartott ilyen sokáig).
Először felmásoltam a fájlt a HDFS-re, külön ügyelve rá, hogy a replikációt 3-ra állítsam, hogy minden gépen legyen egy kópia az adatokból. Arra gondoltam, az a node biztosan nem fog dolgozni, amelyik tárhelyén nincs meg az adat. A CentOS ismét rakoncátlankodott, mert nem volt hajlandó fogadni az adatokat. A master egy ilyen semmitmondó hibaüzenetet adott:
java.io.IOException: Got error, status=ERROR, status message , ack with firstBadLink as 192.168.0.4:9866
A logok szintén nem voltak túl hasznosak, ellenben észrevettem, hogy a webes felületen keresztül sem érem el a CentOS adatnodot. Rövid netes keresgélés után azt találtam, hogy a tűzfal blokkolhatja az adatforgalmat. Ezért a 9864-es portot megnyitottam.
sudo firewall-cmd --zone=public --add-port=9864/tcp --premanent
sudo firewall-cmd --reload
Mindjárt megszűntek a hibaüzenetek, és a másolás megindult. Majdnem 8 órán át másolt, több, mint 130 GB került a HDFS-re, majd az otthoni rouer újraindult, és amit addig másolt, az enyészeté lett. A másolás egyébként azért tartott ilyen sokáig, mert csapat leggyengébb tagja egyik ősrégi gép (Athlon X2-es procival) lassú IDE-s vinyókkal, a hálózati csatolója pedig egy USB2-es wifi adapter.
Második másolásra már okosabban csináltam. Először csak a master gép HDFS-ére másoltam. Ebben SSD volt, ezért viszonylag gyorsan ment a művelet. Utána állítottam be a replikációt 3-ra. Ezzel a módszerrel 5 óra alatt megvolt mindhárom gépen az adat (persze a CentOS-en néhány blokk hiányzott, hogy azért ne legyen meg az örömöm, de ezzel már nem foglalkoztam).
Hatalmas adat, a master mégsem vont be senkit a feldolgozásba, ezért kezdtem arra gyanakodni, hogy egy konfiguráció nem megfelelő. Mivel a replikációk működtek, ezért a HDFS megfelelően kellett, hogy működjön. De mi a helyzet a Yarn-al, ami a számítási feladatok elosztását végzi?
Először egy pi számoló példaprogramot futtattam. A program lefutott, de úgy tűnt, a többi node csak malmozott. Úgy tűnik, ezen még dolgozni kell, de magával a Sparkkal már lehet játszani.