• Nie Znaleziono Wyników

Rozdział 4. Architektura

4.3 Podział operatorów na partycje

4.3.3 Algorytmy tworzenia partycji

[4,3] [4,…] [4,…]

Rys. 4.49. Fragment zapytania przeznaczony do optymalizacji pamięciowej

0 1 2 3 4 5 6 7 8 9 0 3 6 9 Czas P o zo st a ło d o p rz e tw o rz e n ia O1 O2 O3

Rys. 4.50. Wykres obciążenia pamięciowego w funkcji czasu

4.3.3 Algorytmy tworzenia partycji

Optymalizacja jednokryterialna

Optymalizator partycji korzysta z strategii zachłannej. Przyjęto, że na początku zapytanie składa się z jedno-operatorowych partycji, które w kolejnych iteracjach są złączane. Budowa optymalizatora dopuszcza zastosowanie różnych metryk, przy czym metryka składa się z dwóch funkcji. Pierwsza sprawdza czy podana partycja jest obsługiwana. Przykładowo metryki podane w punkcie 5.3.1 dopuszczają tylko prosty łańcuch operatorów lub topologie widelca. Druga funkcja wylicza wartość metryki dla zadanej partycji. Dokładny algorytm podano poniżej.

1) Dla każdej partycji Ei dla zapytania Q, budowana jest potencjalna nowa partycja składająca się z Ei oraz partycji zasilanych przez Ei. Gwarantuje to, że strumienie współdzielone przez kilka operatorów nie są rozpięte pomiędzy kilkoma partycjami. Po zakończeniu tego korku powstaje zbiór potencjalnych nowych partycji.

3) Następnie wyznaczana jest efektywność dla każdej potencjalnej nowej partycji. 4) Wybierana jest partycja z największą i nie ujemną wartością efektywności. 5) Jeżeli w ostatniej iteracji wprowadzono do zapytania nową partycję lub nie

została osiągnięta zadana liczba iteracji N algorytm powraca do punktu 1).

Optymalizacja dwukryterialna

Aby w zrównoważony sposób obniżyć zapotrzebowanie pamięciowe i czasowe skonstruowano optymalizator dwukryterialny, który wyszukuje niezdominowane rozwiązania spośród potencjalnych nowych partycji. Dodatkowo wprowadzono ograniczenie dopuszczające tylko partycje optymalizujące oba kryteria jednocześnie. Podobnie jak w optymalizatorze jednokryterialnym, dobór metryk optymalizacji jest konfigurowalny. Pełen opis algorytmu podano poniżej:

1) Dla każdej partycji Ei dla zapytania Q, budowana jest potencjalna nowa partycja składająca się z Ei oraz partycji zasilanych przez Ei.

2) Usuwane są partycje, które nie są wspierane przez dowolną z obu metryk. 3) Wyznaczana jest efektywność partycji ze względu na obie metryki.

4) Ze zbioru potencjalnych nowych partycji odrzucane są rozwiązania zdominowane.

5) Ze zbioru potencjalnych nowych partycji odrzucane są rozwiązania nieoptymalizujące obu kryteriów jednocześnie.

6) Zbiór potencjalnych nowych partycji jest wprowadzany do pytania Q z uwzględnieniem poniższego przypadku. Przyjmijmy, że mamy trzy operatory tworzące prosty ciąg: O1, O2 i O3. Może dojść do sytuacji, że w zbiorze znajdują się dwie partycje. Jedna partycja E1 wprowadza połączenie: (O1+O2); a druga E2

połączenie (O2+O3). W tym wypadku po wprowadzeniu E1, E2 jest pomijana, ponieważ O2 już nie jest dostępny.

7) Jeżeli w ostatniej iteracji zbiór potencjalnych nowych partycji nie był pusty lub nie została osiągnięta zadana liczba iteracji algorytm powraca do punktu 1).

4.3.4 Testy

Aby uzyskać precyzyjne pomiary obciążenia pamięciowego oraz opóźnień, eksperymenty przeprowadzono na symulatorze opisanym w punkcie 5.2.5. Wzorując

się na środowisku testowym NEXMark [89,66] zdefiniowano test składający się z 32 operatorów. NEXMark zawiera szereg zapytań przetwarzających dane giełdowe. Analizując go od strony połączeń pomiędzy operatorami stworzono test składający się z najczęściej pojawiających się topologii połączeń operatorów. Aby przeprowadzone badania uwydatniły zmiany wydajności pomiędzy różnymi konfiguracjami optymalizatorów uruchomiono jednocześnie 5 kopi testu. Do wygenerowania danych testowych dla każdej kopi użyto rozkłady intensywności zebrane podczas monitoringu pracy rzeczywistych serwerów [81]. Podsumowując, badania zostały przeprowadzone w środowisku składającym się z ponad 150 operatorów, z zastosowaniem zbioru danych, którego rozkład intensywności jest oparty na pomiarach rzeczywistych.

Konfiguracja pojedynczego eksperymentu składała się z ustawienia: obciążenia systemu i algorytmu optymalizacji partycji. Sterowanie obciążeniem systemu zostało zrealizowane dwuetapowo analogicznie jak w punkcie 4.2.4. Przyjęto, że w trakcie eksperymentu uruchamiane jest testowe zapytanie oraz zapytanie wytwarzające dodatkowe obciążenie. Parametry si i ci dla każdego operatora są znane, dlatego możliwe było przeskalowanie czasu napływu danych, aby otrzymać obciążenia CPU na poziomie 50%. Zapytanie wytwarzające dodatkowe obciążenie było zasilane strumieniem, którego krotki definiują czas, przez jaki są obsługiwane. Pomiar wydajności optymalizacji dla zadanej konfiguracji metryk składał się z serii eksperymentów z różnymi poziomami obciążenia. Wszystkie eksperymenty zostały przeprowadzone z zastosowaniem schedulera HNR[76], który jest jednym z wydajniejszych stosowanych w strumieniowych bazach danych. Dla uproszczenia porównań nazewnictwo eksperymentów usystematyzowano. Nazwa każdego eksperymentu składa się z <kryterium><typ metryki optymalizacji>. Wyróżniamy dwa kryteria: HR i Mem, które reprezentują odpowiednio minimalizację czasu odpowiedzi i minimalizację obciążenia pamięciowego. Istnieją także dwa typy metryk: Diff i Eff. Pierwsza oznacza grupę metryk opisaną w punkcie 4.3.1. Drugi typ odnosi się do metryk wprowadzonych w punkcie 4.3.2. Jako przykład, krzywa o nazwie HRDiff reprezentuje wyniki zgromadzone dla optymalizacji czasu odpowiedzi przy użyciu metryki opisanej w sekcji 4.3.1.

Celem opracowania zebranych wyników jest sprawdzenie wydajności minimalizacji obciążenia pamięciowego i minimalizacji czasów odpowiedzi.

W literaturze badania eksperymentalne koncentrują się na pomiarze średniego czasu odpowiedzi lub średniego obciążenia pamięciowego, pomimo że obie wartości średnie mogą zostać łatwo przekłamane przez wartości skrajne. Dlatego pomiar średnich zastąpiono medianą i wartością maksymalną. Wartości maksymalne pozwalają ustalić na ile uzyskane rozwiązanie jest stabilne. Z kolei mediana daje wgląd w przeciętną wydajność optymalizacji. W zebranych pomiarach może zaskoczyć zmierzone zapotrzebowanie pamięciowe, które sięga 200kB. Wartość taka jest wynikiem zastosowanej metody pomiarowej oraz tego, że w NEXMark krotki składają się tylko z kilku atrybutów. Przyjmuje się, że w systemach strumieniowych zmiany zapotrzebowania na pamięć aproksymuje się poprzez pamięć zajmowaną przez krotki w strumieniach, ponieważ system ten nie przechowuje trwale danych. Na rozmiar krotki składa się rozmiar danych, rozmiar struktury tworzącej krotkę oraz rozmiar struktur reprezentujących strumienie. Aby uzyskać pomiar uniezależniony od implementacji krotek i strumieni ograniczono się do pomiaru rozmiaru danych, co umożliwia porównać wydajności konfiguracji pod kątem zapotrzebowania pamięciowego a z drugiej strony abstrahuje od wyboru języka programowania i jakości implementacji.

Rys. 4.51. Obciążenie pamięciowe w funkcji obciążenia systemu

7000 8000 9000 10000 11000 12000 13000 14000 40 60 80 100 120 p a m ć[ B ] obciążenie [%] MemDiffHRDiff MemEffHREff HREffMemDiff HRDiffMemEff HREff MemEff HRDiff MemDiff hnr

Rys. 4.52. Czasy latencji w funkcji obciążenia systemu

Rys. 4.53. Maksymalne wartości obciążenia pamięciowego

1000 1200 1400 1600 1800 2000 2200 2400 2600 40 60 80 100 120 la te n cj a [m s] obciążenie [%] MemDiffHRDiff MemEffHREff HREfflMemDiff HRDiffMemEff HREff MemEff HRDiff MemDiff hnr 0 50000 100000 150000 200000 250000 40 60 80 100 120 p a m ć[ B ] obciążenie [%] MemDiffHRDiff MemEffHREff HREffMemDiff HRDiffMemEff HREff MemEff MemDiff HRDiff hnr

Rys. 4.54. Maksymalne wartości latencji

Na początku przeprowadzono eksperyment bez użycia podziału na partycje, jego wyniki zostały umieszczone na wykresach o nazwach HNR. Stanowi on punkt odniesienia dla osiąganych wydajności po zastosowaniu optymalizacji. Zebrane pomiary pokazują, że dużą rolę odgrywa współpraca pomiędzy schedulerem a optymalizatorem partycji. Zaproponowane nowe metryki MemEff i HREff pozwoliły osiągnąć najkrótsze czasy odpowiedzi w odniesieniu do rozwiązań konkurencyjnych: HNR, HRDiff i MemDiff. Odnotowana poprawa jest rzędu 30%, co obrazuje rys. 4.52. Z perspektywy minimalizacji obciążenia pamięciowego rozwiązanie HREff jest lepsze w odniesieniu do rozwiązania bazowego, a MemEff gorsze co przedstawia rys. 4.51. Przypadek ten jest zaskakujący, ponieważ zastosowanie metryki minimalizującej czas odpowiedzi dało rezultat lepszy od metryki przeznaczonej do minimalizacji obciążenia pamięciowego. Aby wyjaśnić odnotowane zjawisko należy zauważyć, że kryteria optymalizacji obu algorytmów są przeciwne. W przypadku schedulera optymalizowany jest zrównoważony czas opóźnień, z kolei algorytm partycjonowania optymalizuje zapotrzebowanie pamięciowe. W konsekwencji współpraca schedulera z algorytmem tworzącym partycje jest słaba. Podobną obserwację odnotowano dla dwukryterialnego optymalizatora. Sprawdzono kombinacje metryk minimalizaujących pamięć: MemDiff/MemEff oraz minimalizujących czasy

0 50000 100000 150000 200000 250000 40 60 80 100 120 la te n cj a [m s] obciążenie [%] MemDiffHRDiff MemEffHREff HREffMemDiff HRDiffMemEff HREff MemEff HRDiff MemDiff hnr

odpowiedzi: HRDiff/HREff. Wykresy dla tych kombinacji zostały nazwane od nazw wybranych metryk. Przykładowo konfiguracja metryki MemDiff z HRDiff ma nazwę MemDiffHRDiff. Przeprowadzone testy pokazują, że połączenie obu metryk nie pozwoliło osiągnąć efektu synergii.

Zebrane pomiary wartości maksymalnych na rys. 4.53 i rys. 4.54 pozwoliło odnotować interesującą własność. Jeżeli dana konfiguracja prowadziła do minimalizacji mediany czasu odpowiedzi, wtedy również odnotowywana była minimalizacja maksymalnych wartości obciążenia pamięciowego i vice versa. Z punktu widzenia zastosowań, własność ta wskzuje, że stworzenie optymlizatora minimalizaującego czasy odpowiedzi i obciążenie pamięciowe można osignąć łatwiej łącząc minimalizację wartości średnich z minimalizacją wartości maksymalnych zamiast budować optymalizator minimalizujący wartości średnie dla obu kreyteriów. Budowa oraz testy rozwiazania które skorzystałoby z tego spostrzeżenia przewidziane jest w dalszych pracach badawczych.

4.3.5 Wnioski i uwagi

Zaproponowany autorski algorytm optymalizacji podziału operatorów na partycje wyróżnia się dwiema cechami. W przeciwieństwie do istniejących rozwiązań jest on uniwersalniejszy, ponieważ nie ogranicza się do konfiguracji operatorów tworzących prosty ciąg lub rozwidlenie. Ponadto zaproponowane podejście uwzględnia priorytety nadane partycjom przez algorytm schedulera. Dzięki temu na początku tworzone są partycje najkorzystniejsze z punktu widzenia schedulera. Dzięki takiej integracji jak pokazują przeprowadzone testy zaproponowane rozwiązanie pozwala znacząco zmniejszyć czasy odpowiedzi o 30%, przy jednoczesnym utrzymaniu wartości maksymalnych czasów odpowiedzi i zapotrzebowania pamięciowego na niskim poziomie.

W przeprowadzonych badaniach zwrócono również uwagę na metodykę oceny wydajności schedulerów oraz algorytmów tworzenia partycji. Dotąd w pracach koncentrowano się na wartościach średnich. Przeprowadzone testy pokazują, że znaczne różnice pomiędzy rozwiązaniami są odnotowywane, gdy porównamy mediany i wartości maksymalne. Takie zestawienie umożliwia ocenić stabilność rozwiązań. Przykładowo podczas analizy wyników dla optymalizacji

wielokryterialnej, wartości średnie nie ulegały dużym zmianom, podczas gdy wartości maksymalne ulegały mocnemu pogorszeniu.