Apache Hadoop - framework do pisania aplikacji rozproszonych
Transkrypt
Apache Hadoop - framework do pisania aplikacji rozproszonych
Apache Hadoop - framework do pisania aplikacji rozproszonych Piotr Praczyk 5 lipca 2009 1 Wprowadzenie Istnieje wiele rodzajów obliczeń, których wykonywanie na pojedynczej maszynie, nawet najpotężniejszej, jest zbyt czasochłonne. Wśród takich zadań wymienić można analizowanie skomplikowanych danych (na przykład Seti@Home, dane z LHC etc...), albo przetwarzanie ogromnych ich ilości (na przykład Google Maps). Z tego powodu rozwijane są narzędzia ułatwiające wykonywanie obliczeń na wielu komputerach jednocześnie. W przypadku tradycyjnych podejść, programista musi samemu rozwiązywać problemy narastające między innymi kiedy więcej niż jeden działający fragment obliczenia chce uzyskać dostęp do zasobu, kiedy potrzebna jest komunikacja między maszynami itp. Google zaproponował własny paradygmat tworzenia aplikacji rozproszonych, Map Reduce [3] Struktura programów napisanych zgodnie z nim, ułatwia rozwiązywanie wielu skomplikowanych problemów współbieżności automatycznie, ułatwiając zadanie programisty. Przedstawione podejście sprawdza się wyjątkowo dobrze w przypadku programowania zadań wymagających przetwarzania dużych ilości danych. Apache Hadoop jest wolną implementacją Map Reduce. Jest wykorzystywany przez wiele dużych firm takich, jak Yahoo, Amazon czy Facebook. Google posiada własną implementację Map Reduce, którą wykorzystuje wewnętrznie. Hadoop składa się z oprogramowania uruchamianego na maszynach przeznaczonych do wykonywania obliczeń i przechowywania danych oraz z zestawu bibliotek umożliwiających pisanie zadań. Językiem, w którym Hadoop jest napisany, jest głównie Java. Konsekwencją tego jest dostarczenie największej liczby interfejsów programistycznych dla tego języka. Również najbardziej naturalną metodą tworzenia programów działających pod kontrolą Hadoop, jest dostarczenie odpowiednich klas w Javie. Istnieje możliwość wykorzystania dowolnego innego języka programowania. Czasami możliwe jest również uruchomienie istniejącego programu, jako części zadania Map Reduce, bez ingerencji w jego strukturę wewnętrzną. 1 2 Podstawy Map Reduce W najprostszym przypadku, przygotowanie zadania dla Map Reduce, sprowadza się do zaimplementowania dwóch funkcji, map oraz reduce. Konieczne jest również zdefiniowanie położenia danych wejściowych oraz miejsca, gdzie mają być składowane wyniki. Zadaniem funkcji map jest wykonanie pewnych obliczeń na przekazanym jej fragmencie danych wejściowych oraz wygenerowanie ciągu par składających się z klucza oraz przypisanej mu wartości. Dane wygenerowane w tym kroku, są agregowane z wykorzystaniem klucza oraz przekazywane do funkcji reduce. Każde wywołanie reduce związane jest z jednym kluczem oraz listą wszystkich odpowiadających mu wartości. Zadanie funkcji reduce polega na wygenerowaniu par stanowiących wynik obliczenia. Są one zapisywane w lokalizacji wskazanej jako wyjściowa. Rysunek 1 pokazuje strukturę dowolnego obliczenia Map Reduce. Rysunek 1: Elementy zadania Map Reduce Dopóki cały opisany proces odbywa się na jednej maszynie, stosowanie infrastruktury związanej z Map Reduce wiąże się głównie ze stratami wydajności. Jeśli jednak dane wejściowe są odpowiednio duże, implementacja Map Reduce (na przykład Hadoop) zadba o to, aby obliczenia zostały automatycznie rozproszone. Rysunek 2 przedstawia schemat wykonania zadania przygotowanego dla Hadoop na wielu maszynach jednocześnie. Na pierwszy rzut oka, rozwiązanie wydaje się dość niewydajne, ponieważ przesyłanie dużych ilości danych za pośrednictwem sieci jest stosunkowo wolnym procesem. Hadoop stara się umieszczać obliczenia na tych samych maszynach, gdzie przechowywane są dane. Jeśli nie jest to możliwe, obliczenia wykonywane są w miejscach, które są bliskie ze względu na szybkość połączenia sieciowego. Klasycznym przykładem zastosowania paradygmatu Map Reduce, opisanym w [3], jest generowanie statystyk słów pojawiających się w tekście przekazanym jako wejście. Funkcja map, odpowiedzialna może być w takim przypadku za podzielenie otrzymanego napisu na wyrazy oraz wygenerowanie par zawierających wyraz jako klucz oraz liczbę 1 jako wartość. W następnym kroku, framework automatycznie pogrupuje pary ze względu na słowa będące kluczami par. Zadaniem funkcji reduce będzie policzenie, ile par zostało przekazanych dla danego słowa, oraz zwrócenie pary składającej się z rozważanego słowa oraz liczby jego wystąpień. Rysunek 3 pokazuje, jak może przebiegać liczenie słów w przykładowym tekście. 2 Rysunek 2: Struktura rozproszonego Map Reduce Rysunek 3: Liczenie statystyk słów w tekście z wykorzystaniem Map Reduce 3 2.1 Implementacje zadań Domyślnym sposobem implementacji zadań dla Hadoop, jest przygotowanie klas Javy, implementujących interfejsy Mapper oraz Reducer odpowiedzialne odpowiednio za etapy map oraz reduce tworzonego zadania. Oba interfejsy wymagają, aby zostały określone typy par pojawiających się na wejściu oraz wyjściu odpowiednich kroków, z tego powodu są zaimplementowane jako interfejsy generyczne pobierające 4 typy jako argumenty. Składnia dla tych interfejsów przedstawiona jest na listingu 4 Mapper<InputKeyType , InputValType , IntermKeyType , IntermValType> Reducer<IntermKeyType , IntermValType , OutputKeyType , OutputValType> Rysunek 4: Składnia interfejsów wykorzystywanych przy implementacji zadań Map Reduce w Javie 2.2 Odporność na awarie Hadoop został zaprojektowany, aby możliwe było wykonywanie z jego pomocą obliczeń na zwyczajnych komputerach. Wiąże się to z o wiele większą podatnością na awarie i błędy. Jeden z węzłów wykorzystywanego klastra jest odpowiedzialny za śledzenie obliczeń. Jeśli wykryta zostanie awaria, część zadania jest powtarzana na innej maszynie. 3 W jaki sposób wspierane są heurystyki dbające o lokalność obliczeń? Aby możliwe było wykonywanie obliczeń w pobliżu danych przeznaczonych do przetworzenia, konieczne jest posiadanie informacji na temat ich lokacji. Stosowanie zwykłego systemu plików, dostarczanego przez system operacyjny nie jest dobrym rozwiązaniem ze względu na wysoki poziom abstrakcji danych. W przypadku systemów unixowych, system stara się ukryć szczegóły dotyczące fizycznego przechowywania danych poprzez utrzymywanie wirtualnego drzewa katalogów. Dzięki temu możliwe jest działanie tych samych programów na różnych zbiorach danych, często przechowywanych w sposób nie rozważany w trakcie pisania aplikacji. Jednocześnie jednak program taka nie jest w stanie odróżnić, czy plik znajduje się na lokalnej maszynie, czy może jest jedynie widoczny za pośrednictwem sieciowego systemu plików a zatem nie jest w stanie określić, jak kosztowne będzie jego odczytanie. Z tego powodu konieczne jest zastosowanie innych rozwiązań. 4 3.1 HDFS Domyślną metodą przechowywania danych przez Hadoop jest dedykowany rozproszony system plików, HDFS (Hadoop Distributed File System). Został on zaprojektowany, aby zoptymalizować wykonywanie czynności związanych z Map Reduce, takich jak szybki dostęp do dużych, spójnych obszarów danych, udostępnianie informacji o fizycznym ich położeniu, tworzenie kopii danych na innych maszynach zgodnie z topologią sieci. Aby przyspieszyć powyższe operacje, niektóre standardowe wymagania stawiane przed systemem plików, wymienione w specyfikacji POSIX, nie zostały spełnione. W HDFS wspierany jest model, według którego pliki zapisywane są tylko raz, lecz mogą być odczytywane wielokrotnie. Możliwe jest również dopisywanie danych na końcu istniejących już plików, jednak w obecnej wersji funkcjonalność ta nie jest jeszcze uważana za stabilną. Aby zapewnić całkowitą lokalność danych, te same maszyny powinny być wykorzystywane do obliczeń jak i przechowywania danych. Ze względu na to, że zadania Map Reduce, z natury przetwarzają duże ilości danych, system plików HDFS posiada duży rozmiar bloku. Dzięki temu, obciążenie związane z przechowywaniem i uzyskiwaniem metadanych jest o wiele mniejsze niż w przypadku standardowych rozwiązań. konsekwencją takiego podejścia jest jednak to, że HDFS nie nadaje się do przechowywania wielu małych plików [4]. Za każdym razem kiedy plik jest zapisywany, najmniejsza liczba bloków dostarczająca potrzebnej przestrzeni dyskowej, jest alokowana. Jeśli plik nie wykorzystuje pełnego bloku, reszta pozostaje pusta. Uruchamiając zadanie Hadoop, jako parametr można przekazać foldery służące do przechowywania tych danych. Wszystkie operacje na plikach zostaną wykonane automatycznie a program otrzyma na wejściu odpowiednie pary. Istnieje sterownik wykorzystujący bibliotekę Fuse, który pozwala na zmontowanie HDFS w drzewie katalogów. Domyślnym sposobem dostępu do systemu plików jest jednak wywołanie Hadoop z parametrem dfs. Udostępniane operacje są podobne do tych udostępnianych przez powłokę systemową w stosunku do zwykłych systemów plików. 3.2 HBase Czasami system plików nie jest najlepszym rozwiązaniem. Może tak się zdarzyć, kiedy na przykład specyfika rozwiązywanego problemu wymaga przechowywania wielu niewielkich porcji danych. HBase jest implementacją rozproszonej bazy danych BigTable, przedstawionej przez Google w [2]. HBase nie jest relacyjną bazą danych, lecz tak zwanym Key-value store. Dane przechowywane są w strukturze przypominającej wielopoziomowy słownik. Kluczami są dowolne ciągi bajtów. Dane są fizycznie przechowywane w kolejności leksykograficznej względem klucza, co pozwala na szybkie wyszukiwanie oraz na pewne optymalizacje przy tworzeniu zadań. 5 Podobnie, jak w przypadku HDFS, HBase została zoptymalizowana pod kątem operacji typowych dla Map Reduce. Zrezygnowano z funkcjonalności, które były kosztowne w przypadku rozproszonych, relacyjnych baz danych. Z tego powodu nie ma możliwości definiowania logicznych powiązań między danymi, takich jak klucze obce. Również obsługa transakcji jest bardzo okrojona i ogranicza się do atomowego wykonywania ciągu operacji dotyczących jednego wiersza. W chwili pisania tego teksu, jedynie API dla języka Java było dostępne. 3.3 Możliwość implementacji własnych formatów wejściowych Lista możliwych źródeł danych wejściowych oraz sposobów zapisywania wyników nie ogranicza się do opisanych powyżej. Możliwe jest wykorzystanie tradycyjnych systemów plików oraz relacyjnych baz danych, w przypadku których korzyści związane z lokalnością obliczeń zostaną utracone. Istnieje również możliwość implementacji własnych źródeł danych. Zadanie takie sprowadza się do napisania zestawu klas w Javie, implementujących interfejsy InputFormat, RecordReader oraz InputSplit. Dzięki temu możliwa jest współpraca zadań Hadoop z dowolnymi nośnikami, możliwe jest konwertowanie danych w locie a nawet generowanie ich w czasie wykonania. Sytuacja wygląda podobnie w przypadku sposobów przechowywania wyników. 4 Alternatywne metody implementacji zadań Map Reduce Często implementacja zadań w języku Java nie jest najwygodniejszym rozwiązaniem. Powodem mogą być sytuacje kiedy zamknięta biblioteka programistyczna, niedostępna w Javie, musi zostać wykorzystana. Czasami wygodne mogło by być również wykorzystywanie gotowych programów, jako zadań Map Reduce. Hadoop udostępnia dwa interfejsy pozwalające na wykorzystanie innych języków programowania. Stosowanie ich wiąże się z pewnymi ograniczeniami w stosunku do stosowania natywnej implementacji. W niektórych sytuacjach może być jednak wygodne. 4.1 Streaming Najbardziej uniwersalnym interfejsem programistycznym jest Hadoop Streaming. Pozwala on na wykorzystanie dowolnego programu w obu krokach wykonywania zadania Map Reduce. Dane wejściowe przekazywane są za pomocą standardowego wejścia. Dane wyjściowe powinny zostać przekazane przez standardowe wyjście. Ponieważ dane składają się z ciągu par klucz, wartość, zdefiniowany jest sposób interpretacji napisów. Każda linia koduje jedną parę. Istnieje możliwość zdefiniowania separatora. W obecnej wersji Hadoop nie wspiera przekazywania 6 danych binarnych przy stosowaniu Streamingu, są jednak plany zaimplementowania tej funkcjonalności w przyszłości. Dzięki opisanemu sposobowi komunikacji z frameworkiem, możliwe jest wykorzystanie istniejących programów jako zadań Hadoop. Możliwe jest również uruchamianie ciągów poleceń powłoki. 4.2 Pipes Kolejny z dostarczonych interfejsów programistycznych jest dedykowany dla języka C++. Zamiast implementacji klas w Javie, umożliwia on dostarczenie klas C++. Muszą one dziedziczyć po klasach zdefiniowanych w odpowiednim pliku nagłówkowym będącym częścią dystrybucji Hadoop. Rozwiązanie te jest mniej uniwersalne, jednak pozwala na większą kontrolę nad zadaniem. Dzięki zastosowaniu struktur danych języka programowania, łatwy jest dostęp do wewnętrznych struktur opisujących zadanie. Są one mapowane na odpowiednie obiekty C++. Podobnie, jak w przypadku stosowania Streamingu, pojawiają się problemy przy przekazywaniu danych binarnych. Przy zastosowaniu SWIG, możliwe jest stworzenie wrapperów dla wielu języków programowania. Stosowanie zarówno Hadoop Pipes jak i Streamingu, może łączyć się z wykorzystaniem dowolnych formatów wejściowych, wyjściowych oraz innych wtyczek dla Hadoop. Elementy te muszą być jednak zaimplementowane w Javie. 5 Projekty związane z Map Reduce Poza HBase, istnieją również inne projekty związane z Hadoop, rozszerzające jego możliwości albo pozwalające na wykonywanie konkretnych rodzajów obliczeń. Kilka przykładów zostało opisanych poniżej. 5.1 Dumbo Dumbo jest biblioteką języka Python, oraz zestawem narzędzi usprawniających pisanie zadań korzystających z Hadoop Streaming. Wśród dostarczanych udogodnień, warto wymienić automateczne parsowanie wejścia i przekazywanie go do funkcji map i reduce za pomocą odpowiednich struktur danych oraz wsparcie dla przekazywania danych binarnych. 5.2 Hama Hama jest biblioteką pozwalającą na wykonywanie operacji na dużych macierzach z wykorzystaniem Map Reduce a w szczególności Hadoop. W obecnym stadium rozwoju brakuje jej wiele funkcji, jak liczenia wartości własnych, w związku z czym jest rozwijana w ramach Apache Incubator. 7 5.3 Mahout Projekt Mahout ma na celu dostarczenie bibliotek wspomagających uczenie maszynowe, wykorzystujących Hadoop w celu wykonywania obliczeń. 5.4 Hadoop a Cloud Computing Najbardziej oczywistą metodą uzyskania dostępu do klastra działającego pod kontrolą Hadoop jest własnoręczne skonfigurowanie takiego. Nie jest to jednak jedyna możliwość. Firma Amazon, udostępnia instalację Hadoop w ramach swoich serwisów Cloud Computing [1]. Korzystając ze strony internetowej, możliwe jest uruchomienie dowolnej liczby maszyn mających wykonywać zadania Map Reduce. Opłaty pobierane są od godziny działania instalacji. Dzięki takiemu podejściu, możliwe jest dynamiczne rezerwowanie oraz zwalnianie potrzebnych zasobów co może prowadzić do zmniejszenia kosztów działania instalacji. Niekorzystnym efektem pojawiającym się przy stosowaniu rozwiązania Amazon jest to, że dane trzymane są domyślnie w sieciowym systemie plików S3. W efekcie, rozwiązanie nie korzysta z lokalności obliczeń. Czasami jednak, na przykład kiedy ilość obliczeń jest duża w porównaniu z ilością danych, nie ma to dużego znaczenia. 5.5 Couldera Firma Cloudera dostarcza komercyjną dystrybucję Hadoop zawierającą dodatkowe narzędzia konfiguracyjne. Oferuje również wsparcie techniczne. 6 Podsumowanie Map Reduce wydaje się być dobrą alternatywą dla standardowych API umożliwiających pisanie aplikacji rozproszonych. Wiele problemów daje się wyrazić za pomocą tego paradygmatu w bardzo naturalny sposób, czyniąc powstałe programy bardziej czytelnymi. Pomimo stosunkowo wczesnej fazy rozwoju, projekt Hadoop udowodnił już swoją przydatność. Wiele znanych firm wykorzystuje go do przetwarzania danych na wielką skalę. Dzięki przejrzystej strukturze Map Reduce, łatwo jest zacząć pisać własne zadania działające pod kontrolą Hadoop. Implementacja pozwalająca pisać własne wtyczki, jak na przykład formaty wejścia i wyjścia, zwiększa rozdział komponentów programu sprawiając, że podatność na błędy jest o wiele mniejsza. Literatura [1] Amazon elastic mapreduce. [2] F. Chang, J. Dean, S. Ghemawat, W. C. Hsieh, D. A. Wallach, M. Burrows, T. Chandra, A. Fikes, and R. E. Gruber. Bigtable: a distributed storage 8 system for structured data. In OSDI ’06: Proceedings of the 7th symposium on Operating systems design and implementation, pages 205–218, Berkeley, CA, USA, 2006. USENIX Association. [3] J. Dean and S. Ghemawat. Mapreduce: simplified data processing on large clusters. Commun. ACM, 51(1):107–113, 2008. [4] T. White. The Small Files Problem. 9