hadoop lab 1: konfiguracja w laboratoriach MIMUW; word count
Będziemy używać hadoopa uruchomianego na komputerach w wydziałowych laboratoriach. Każdy ze was będzie tworzył swój własny klaster hadoopa; w tym celu prościej jest używać hadoopa w wersji 1.x niż 2.x (2.x umożliwia lepsze zarządzanie wieloma użytkownikami i wieloma zadaniami w ramach jednego klastra). Aplikacje hadoopa używają HDFS, rozproszonego systemu plików. Węzłami HDFS będą te same komputery na których przeprowadzać będziemy obliczenia. HDFS przechowuje dane na lokalnych dyskach twardych (/tmp/
), które są okresowo czyszczone.
Programy można też testować na pojedynczej maszynie na której stawiamy wiele procesów hadoopa: http://hadoop.apache.org/docs/r1.2.1/cli_minicluster.html
Do programowania będziemy wykorzystywać "stare" (oryginalne) API (pakiet org.apache.hadoop.mapred); nowe API jest w pakiecie org.apache.hadoop.mapreduce. Różnice między API są w prezentacji: http://www.slideshare.net/sh1mmer/upgrading-to-the-new-map-reduce-api
Pliki:
- http://mimuw.edu.pl/~krzadca/mimuw-hadoop-1.2.1.tgz (tutorial instalacyjny poniżej)
- http://mimuw.edu.pl/~krzadca/hadoop-programy.tgz (programy i skrypt build.xml, po rozpakowaniu, umieść katalog programy jako podkatalog dystrybucji hadoopa).
1 Alternatywy
Hadoop można też uruchamiać lokalnie na pojedynczym komputerze jako oddzielny proces (pseudo-distributed); albo na pojedynczym komputerze w tym samym procesie co testowany programem (stand-alone).
1.1 Uruchamianie programu w jednym procesie razem z hadoopem (w eclipse; stand-alone)
- stwórz projekt w eclipse
- dodaj do project properties->java build path->libraries wszystkie jary z hadoop/lib i hadoop-core z hadoop
- Stwórz klasę MyWordCount i wklej zawartość z naszych materiałów ( http://mimuw.edu.pl/~krzadca/hadoop-programy.tgz ).
- Stwórz katalog z danymi wejściowymi 'input' jako podkatalog katalogu głównego projektu; dodaj tam kilka plików tekstowych.
- Stwórz nową konfigurację uruchomieniową: project properties -> run/debug settings -> new configuration; ustaw katalog wejściowy (input) i wyjściowy (output) w zakładce program arguments
- Przed każdym uruchomieniem usuń katalog wyjściowy (output).
1.2 Uruchamianie hadoopa w oddzielnym procesie (pseudo-distributed)
W tej wersji uruchamiamy hadoopa jako oddzielny proces (serwera) na jednym węźle. Programy obliczeniowe będą komunikowały się z tym serwerem tak, jakby hadoop uruchomiony był
2 Przygotowania
Upewnij się, że możesz zalogować się przez ssh bez podawania hasła na wybrane komputery (w tym tutorialu: violet02
, violet05
i violet06
). Zwykle pierwszy raz musisz zalogować się podając hasło. Zaloguj się na pierwszy z komputerów z tej listy.
3 Instalacja klastra w laboratoriach mimuw
Instalacja klastra polega na instalacji i uruchomieniu systemu plików HDFS (składa się z namenode, czyli węzła tłumaczącego nazwy plików na ich lokalizacje; oraz datanodes, czyli węzłów przechowujących dane); oraz na uruchomieniu systemu obliczeń map-reduce (składa się z jobtracker, czyli węzła zlecającego zadania i kontrolującego ich postęp; oraz tasktrackers, czyli węzłów wykonujących zlecone zadania).
W naszej instrukcji procesy namenode i jobtracker będą działać na tym samym komputerze, zwanym poniżej kontrolerem.
Jeśli coś nie działa:
- problemem może być usiłowanie korzystania przez hadoop z zajętego portu. Zmodyfikuj wartość
first_port
w skrypciemimuw-config.py
. - inny problem to niezgodność ID w systemie plików HDFS (błędy w logach datanodes); w takim przypadku najprościej jest usunąć katalogi
/tmp/hadoop-XX123456
ze wszystkich węzłów, a następnie przeformatować system plików. - do zabijania hadoopa i czyszczenia danych HDFS z innych hostów możesz użyć skryptu
mimuw-cleanup.py
.
Instrukcje:
- Ściągnij naszą dystrybucję hadoopa: http://mimuw.edu.pl/~krzadca/mimuw-hadoop-1.2.1.tgz
Dystrybucja ma ustawioną zmienną JAVA_HOME
w conf/hadoop-env.sh
; oraz dodany skrypt ustawiający najważniejsze pliki konfiguracyjne.
- Rozpakuj dystrybucję w swoim katalogu domowym; powstanie katalog
~/hadoop
. - Przejdź do katalogu
~/hadoop
. - Do pliku
hosts
wpisz nazwy hostów na których postawisz klaster (jedna nazwa w linii); pierwszy host z tej listy będzie kontrolerem (master node) systemu plików i obliczeń. Jako pierwszy host wpisz nazwę komputera przy którym siedzisz. - Uruchom skrypt
$ python mimuw-config.py
Skrypt ten wygeneruje pliki konfiguracyjne hadoopa: conf/slaves
(węzły używane do obliczeń) i wpisze koordynatora do conf/core-site.xml
, conf/mapred-site.xml
i conf/hdfs-site.xml
. Uwaga: zapisz adresy które ten skrypt generuje: np: jobtracker: http://violet02:37770
i namenode: http://violet02:37780
- Sformatuj system plików HDFS:
$ bin/hadoop namenode -format
Uwaga: jeśli formatujesz drugi raz, hadoop prosi o potwierdzenie; upewnij się, że wciskasz duże 'Y'.
Szukaj informacji o sukcesie formatowania:
14/04/25 15:13:27 INFO common.Storage: Storage directory /tmp/hadoop-krzadca/dfs/name has been successfully formatted.
- Uruchom hadoop:
$ bin/start-all.sh
Na konsoli powinny zostać wypisane logi podobne do (zwróć uwagę, że uruchamiane są wszystkie 3 węzły):
starting namenode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-namenode-violet02.out Picked up _JAVA_OPTIONS: -Xmx384M Picked up _JAVA_OPTIONS: -Xmx384M violet05: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet05.out violet06: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet06.out violet02: starting datanode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-datanode-violet02.out localhost: starting secondarynamenode, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-secondarynamenode-violet02.out starting jobtracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-jobtracker-violet02.out Picked up _JAVA_OPTIONS: -Xmx384M Picked up _JAVA_OPTIONS: -Xmx384M violet05: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet05.out violet02: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet02.out violet06: starting tasktracker, logging to /home/staff/iinf/krzadca/hadoop/libexec/../logs/hadoop-krzadca-tasktracker-violet06.out
- Sprawdź czy hadoop działa poprawnie. Logi są w katalogu
logs
; informacje diagnostyczne są dostępne pod adresem namenode zapisanym w poprzednim punkcie (upewnij się, że strona jobtrackera podaje 3 aktywne węzły, live nodes; oraz że strona namenode podaje 3 aktywne węzły).
W następnych krokach będziemy testować poprawność działania systemu używając aplikacji grep
z dystrybucji hadoopa.
- Przekopiuj dane wejściowe z lokalnego katalogu
hadoop/data-txt
(gdzie, z okazji Roku Szekspirowskiego, znajdziesz kilka jego sztuk) do katalogu HDFSinput-data-txt
:
$ bin/hadoop fs -put data-txt input-data-txt
- Sprawdź zawartość katalogu HDFS
input-data-txt
używając:bin/hadoop fs -ls input-data-txt
lub interfejsu http namenode (którego adres wyprodukował skrypt pythona) (powinny być te same pliki co w lokalnym kataloguhadoop/data-txt
).
$ bin/hadoop fs -ls input-data-txt
Found 6 items -rw-r--r-- 1 krzadca supergroup 125759 2016-05-23 15:26 /user/krzadca/input-data-txt/burza.txt -rw-r--r-- 1 krzadca supergroup 95146 2016-05-23 15:26 /user/krzadca/input-data-txt/komedia-omylek.txt -rw-r--r-- 1 krzadca supergroup 121195 2016-05-23 15:26 /user/krzadca/input-data-txt/makbet.txt -rw-r--r-- 1 krzadca supergroup 150132 2016-05-23 15:26 /user/krzadca/input-data-txt/poskromienie-zlosnicy.txt -rw-r--r-- 1 krzadca supergroup 161943 2016-05-23 15:26 /user/krzadca/input-data-txt/romeo-i-julia.txt -rw-r--r-- 1 krzadca supergroup 117135 2016-05-23 15:26 /user/krzadca/input-data-txt/sen-nocy-letniej.txt
- Uruchom grep, aplikacje hadoopa:
$ bin/hadoop jar hadoop-examples-*.jar grep input-data-txt output '\bse\w+'
W czasie gdy aplikacja działa, możesz oglądać jej postęp przez interfejs http (adres: jobtracker)
- Obejrzy logi (
logs/
): w logu jobtracker powinny pojawić się informacje o uruchamianiu tasków na każdym z węzłów (szukaj linii:Adding task (MAP) ... to tip ... for tracker ...
) - Obejrzyj rezultat wykonania grep który został zapisany w katalogu
output
HDFS (lub przez http, adres: namenode).
$ bin/hadoop fs -ls output
Found 3 items -rw-r--r-- 1 krzadca supergroup 0 2016-05-25 15:16 /user/krzadca/output/_SUCCESS drwxr-xr-x - krzadca supergroup 0 2016-05-25 15:16 /user/krzadca/output/_logs -rw-r--r-- 1 krzadca supergroup 52 2016-05-25 15:16 /user/krzadca/output/part-00000
Plik z wynikami:
$ bin/hadoop fs -cat output/part-00000
69 serce 68 serca 33 sen 20 sercu 5 sekutnica ...
Pliki można też skopiować z HDFS do systemu plików przez:
bin/hadoop fs -get output output-local cat output-local/*
- Zamknij hadoop
$ bin/stop-all.sh
4 Kontrola zadań
Lista zadań wykonujących się na klastrze:
$ bin/hadoop job -list
Uwaga: ctrl-c nie przerywa wykonania zadania!
Przerywanie zadania
$ bin/hadoop job -kill JobId
5 Proste map-reduce w hadoopie
5.1 Map
public static class MapClass extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(LongWritable key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { String line = value.toString(); StringTokenizer itr = new StringTokenizer(line); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); output.collect(word, one); } } }
5.2 Reduce
public static class Reduce extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> { public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException { int sum = 0; while (values.hasNext()) { sum += values.next().get(); } output.collect(key, new IntWritable(sum)); } }
5.3 Główny program
public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); JobConf job = new JobConf(conf, MyWordCount.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); job.setOutputFormat(TextOutputFormat.class); job.setInputFormat(TextInputFormat.class); job.setMapperClass(MapClass.class); job.setReducerClass(Reduce.class); job.setCombinerClass(Reduce.class); FileInputFormat.setInputPaths( job, new Path( args[0] ) ); FileOutputFormat.setOutputPath( job, new Path( args[1] ) ); job.setJobName( "MyWordCount" ); // Run the job JobClient.runJob(job);
5.4 kompilowanie i uruchamianie
cd programy ant cd .. bin/hadoop jar programy/dist/mimuw-lab1.jar MyWordCount input-data-txt output
6 liczenie znaków (zadanie zaliczeniowe, 0.5 pkt)
Napisz program, który zliczy wystąpienia każdego znaku w plikach wejściowych, tzn. dla wejścia: "ala ma kota" wyjściem powinno być (przy czym kolejność linii na wyjściu nie ma znaczenia):
a 4 l 1 2 m 1 j 1 k 1 o 1
Zacznij od szablonu z CharacterCount.java
.
7 liczenie bigramów (zadanie zaliczeniowe, 0.5 pkt)
Bigram to para słów. We fragmencie "Wesoły jestem, wesoły" Wyspiańskiego (za http://literat.ug.edu.pl/~literat/wyswier/040.htm ):
Wesoły jestem, wesoły i śmieję się do łez
bigramy to:
(wesoły jestem) (jestem wesoły) (wesoły i) (i śmieję) (śmieję się) (się do) (do łez)
Napisz program, który dla każdego słowa liczy sumę jego wystąpień w tekście oraz wypisuje względne częstości słow występujących po tym słowie. Do wyłuskiwania słów z polskimi znakami możesz użyć wyrażenia regularnego \p{L}+
.
Przykład:
(wesoły *) 2 (wesoły jestem) 0.5 (wesoły i) 0.5 (jestem *) 1 (jestem wesoły) 1 (i *) 1 (i śmieję) 1 (śmieję *) 1 (śmieję się) 1 (się *) 1 (się do) 1 (do *) 1 (do łez) 1