Eugenia Busłowska 1, Łukasz Juźwiuk 2 Politechnika Białostocka, Wydział Informatyki, Katedra Systemów Informacyjnych i Sieci Komputerowych. Wprowadzenie do optymalnego wykorzystania MapReduce 1. Wstęp We współczesnym świecie systemy informatyczne generują coraz większe ilości cyfrowej informacji. Są to dane tworzone przez człowieka, ale również i maszyny takie jak urządzenia pomiarowe czy instalacje naukowe. Roczny przyrost danych w wielu firmach oraz instytucjach nieraz przekracza 1 petabajt (PB) danych. Problem zarządzania nieprzeciętnie dużą ilością danych dotyczy również logistyki. Zastosowanie elektronicznych baz danych do przechowywania informacji spowodowało możliwość przechowywania niewyobrażalnych ich ilości. Przepływ informacji wymaga ciągłego udzielania odpowiedzi na zadawane pytania do danych, co z kolei powoduje konieczność przetworzenia zapytań. Przyśpieszenie wykonania zapytań w standardowym podejściu wymusza, utworzenie odpowiednich indeksów, które uporządkowują dane według narzuconych kryteriów powodując szybkie przeszukiwanie zgromadzonych dokumentów. Im więcej danych tym dłuższy czas ich pobierania. Przykładowo, czas pobrania 1 tetabajt (TB) danych łączem 8 Mbit to około 11 i pół dnia. Czas ten nie jest obecnie akceptowalny, dlatego w celu przetwarzania tak dużych ilości danych w relatywnie krótkim i możliwie najmniejszym nakładem pracy korporacja Google opracowała i opublikowała w roku 2004 abstrakt na temat paradygmatu MapReduce. [1] 2. Idea MapReduce Podstawnym założeniem paradygmatu MapReduce jest podział problemu na dwa główne etapy nazywane mapowaniem i redukcją. W praktyce przy bardziej złożonych problemach często zachodzi potrzeba łączenia tych etapów w tak zwane łańcuchy. Najkrótszy łańcuch może składać się z jednego mapera. Przy tworzeniu łańcuchów należy pamiętać, że każdy etap redukcji musi być poprzedzony przynajmniej jednym etapem mapowania. Przykładowym łańcuchem może być praca MapReduce zbudowana z np.: [Map1 Map2 Reduce1 Map3]. Praca składa się ze wstępnego przetwarzania Map1, późnego przetwarzania Map2, właściwej redukcji Reduce1 oraz końcowego przetwarzania w Map3. Jeżeli problemu nie udało się zrealizować za pomocą łączenia etapów pozostaje jeszcze mniej wydajne, lecz dające większe możliwości łączenie prac MapReduce. Rozbicie na dwie prace wcześniejszego przykładu mogłoby wyglądać następująco: [Map1] [Map2 Reduce1 Map2]. Potrzeba rozbicia na dwie prace może zajść wtedy, gdy dane otrzymane w pierwszej pracy muszą zostać rozdystrybuowane do wszystkich niezbędnych węzłów przed przystąpieniem do przetwarzania danych przez Map2. [1] 3. Dane i ich transfer Dane w klastrze opartym o paradygmat MapReduce w zdecydowanej większości znajdują się w rozproszonym systemie plików. Niniejszy system plików został opisany w innym abstrakcie przedstawionym w roku 2003 przez firmę Google na temat Google File System (GFS). Rozproszony system plików w połączeniu z MapReduce pozawala na przetwarzanie danych w miejscu ich przechowywania. Dzięki temu rozwiązaniu nie ma potrzeby transferu informacji z maszyn magazynujących dane o małej mocy obliczeniowej do potężnych 1 E-mail: ebuslowska@pb.edu.pl 2 E-mail: lukjuz@gmail.com 3870
serwerów. Zamiast przesyłać dane (nieraz kilka terabajtów lub więcej) wysyłany jest program MapReduce o rozmiarach kilku kilobajtów. Zyskiwany jest cenny czas potrzebny na transfer. Ta oraz kilka innych, pominiętych tutaj cech powoduje, że MapReduce wraz z DFS (Distributed File System) pozwala na osiągnięcie liniowej skalowalności klastra obliczeniowego. Dobrą praktyką jest stosowanie typów binarnych w celu ograniczenia rozmiarów danych. Dla zrównoważenia oraz przyśpieszenia replikacji w rozproszonym systemie plików stosuje się sekwencjonowanie z użyciem znaczników, co wprowadza nieznaczną nadmiarowość w zależności od długości sekwencji. Przykładowym typem binarnym plików może być SequenceFile powszechnie wykorzystywany przez platformę Hadoop. [2] Rys. 1. Podgląd wykonania. Źródło: Yahoo Możliwa jest również automatyczna kompresja danych z wykorzystaniem różnych algorytmów. Kompresję w MapReduce stosuje się na trzech typach danych: wejściowych(1), pośrednich(2) i wyjściowych(3) widocznych na Rys. 1. 3871
Rys. 2. Kompresja danych w MapReduce. Źródło: Yahoo, Hadoop Summit 2013 Aby porównać wydajności przy kompresji bierze się pod uwagę niezbędny czas na kompresję i dekompresje danych w stosunku do zyskanego rozmiaru. Kodeki kompresujące dzieli się na dwie główne grupy; o dużej szybkości oraz o dużym współczynniku kompresji. Na Rys 3. przedstawiono porównanie wydajności dla różnych kodeków przy kompresji tekstu z artykułów zamieszczonych na portalu Wikipedia. Ze względu na swoje cechy stosuje się różne kodeki na różnych etapach pracy MapReduce. 3872
Rys. 3. Porównanie wydajności kompresji na korpusie tekstów z Wikipedii. Źródło: Yahoo, Hadoop Summit 2013 4. Mapper Mapowanie polega na pobraniu danych ze źródła przy użyciu czytnika rekordów oraz ewentualnym przefiltrowaniu ze względu na zadane kryteria, projekcji jak również przetworzeniu. Etap ten jest ściśle równoległy. Oznacza to, że każdy wiersz danych podany do mapera jest traktowany, jako oddzielna informacja niemająca wpływu na odczyt pozostałych. Każda instancja mapera tworzy listę danych wyjściowych w postaci list<k1,v1>, gdzie K1 jest kluczem, a V1 wartością. Na kolejnym etapie zwanym shuffle zawartość wszystkich list domyślnie zostaje posortowana w celu możliwie równomiernego rozłożenia danych przeznaczonych dla reduktorów. Powinno dążyć się do realizacji problemu z wykorzystaniem jedynie maperów. Zaletą takiego rozwiązania jest uniknięcie czasochłonnego równoległego sortowania danych wyjściowych oraz ich późniejszego przesłania do reduktorów. [3] Na tym etapie spotyka się dwa główne problemy. Pierwszym z nich jest pytanie jak równomiernie podzielić dane wejściowe, aby wszystkie mapery zakończyły pracę w możliwie najmniejszym odstępie czasowym. Jest to ważne gdyż nadmierne obciążenie zaledwie jednego z maperów opóźnia przejście do kolejnego etapu w łańcuchu MapReduce. Drugim problemem jest redundancja danych wyjściowych z mapera. Pamiętając o równoległości mapera wysoce niewydajne jest dbanie na tym etapie o niepowtarzanie się rekordów w list<k1,v1>. Jednak z pomocą przychodzi Combiner, który zostanie opisany w jednej z kolejnych części artykułu. 5. Partitioner i Shuffle Partycjoner odpowiedzialny jest za logiczny podział danych wyjściowych z mapera. Podejmuje on decyzję, do którego reduktora powinien trafić dany rekord ze względu na zadaną cechę. W platformie Hadoop domyślnie używany jest HaszPartitioner, który przydziela dane do reduktorów ze względu na hash klucza. W 3873
większości przypadków w celu równomiernego rozłożenia obciążenia reduktorów zachodzi potrzeba napisania własnego partycjonera wraz z porównywaczem (comparator). Otrzymujemy wtedy optymalny mechanizm podziału danych pośrednich ze względu np. na żądaną cechę a nie hash. Shuffle zazwyczaj jest najbardziej kosztownym etapem pracy MapReduce. Dlatego jest bardzo ważne, aby danych wyjściowych z mapera było możliwie najmniej. Ważne jest również, aby miały one jak najmniejszy rozmiar ze względu na to, że odbywa się M R transferów danych pomiędzy węzłami, gdzie M jest liczbą obiektów mapujących, a R liczbą obiektów redukujących. [4] 6. Reducer oraz Combiner Reduktor w odróżnieniu do mapera z założenia jest ściśle sekwencyjny. Oznacza to, że wynik tego etapu jest określony przez całą populację danych wejściowych o określonej cesze. Skutkiem takiego podejścia jest niemożność rozpoczęcia redukcji przed zakończeniem poprzedzającego etapu mapowania. Na tym etapie najważniejszym zadaniem stawianym przed programistą jest stworzenie jak najlepszego algorytmu realizującego dany problemu. W dużych klastrach MapReduce mających liniową skalowalność, może być znacznie bardziej opłacalna optymalizacja kodu aniżeli dokupienie dodatkowych serwerów. Dlatego zaleca się ciągłą pracę nad możliwym jak największym obniżeniem złożoności obliczeniowej użytych algorytmów bądź ich zastąpienie. [5] Jeżeli w danych pośrednich stwierdzono duży stopień redundancji kluczy zaleca się użycie combinera. Combiner umożliwia wykonanie reduktora na danych z węzła mapującego przed przekazaniem ich do partycjonera. Ograniczamy wtedy ilość danych pośrednich przesyłanych pomiędzy węzłami klastra oraz przyśpieszamy fazę redukcji realizując cząstkowe obliczenia. [5] Rys. 3. Zastosowanie combinera. Źródło: Yahoo 3874
Streszczenie Artykuł ma na celu przedstawienie krytycznych punktów w MapReduce prowadzących do utraty lub zysku w wydajności. Jest to wstęp do dokładniejszej analizy poszczególnych faz wykonania występujących w większości implementacji z wykorzystaniem tegoż paradygmatu. Poruszane są ogólne zagadnienia związane z danymi, mapowaniem, redukcją, partycjonowaniem oraz kilka innych. Introduction to the optimal use of MapReduce Abstract Purpose of the paper is to create simple overview of critical points for performance in MapReduce. This is introduction to more detailed analysis of execution phases being part of the most issues implemented using said paradigm. Discussed are general issues related to data, mapping, reduction, partitioning and several others. Key words: MapReduce, Hadoop, Big data 7. Literatura [1] J. Dean, S. Ghemawat: MapReduce: Simplified Data Processing on Large Clusters, OSDI 04: Sixth Symposium on Operating System Design and Implementation, San Francisco, CA, 2004, http://research.google.com/archive/ mapreduce.html. [2] Ch. Lam: Hadoop in Action, Manning, 2010. [3] A. Holmes: Hadoop in Practice, Manning, 2012. [4] G. Kamat, S. Singh: Compression Options in Hadoop A Tale of Tradeoffs, Hadoop Summit, 2013, http://www. slideshare.net/hadoop_summit/kamat-singh-june27425pmroom210cv2. [5] M. Bhandarkar: Practical Problem Solving with Hadoop and Pig, Middleware, 2009, http://www.slideshare.net/ hadoop/practical-problem-solving-with-apache-hadoop-pig. 3875