Subsections

6 Testowanie systemu


1 Dane testowe

Do przeprowadzenia testów potrzebowałem zbiór adresów istniejących stron WWW. Strony te powinny przypominać swoją różnorodnością strony odwiedzane (a więc i śledzone) przez użytkowników WWW -- oczywiście z punktu widzenia komputera, a nie zawartości w rozumieniu ludzkim. Zależało mi więc na wykorzystaniu: Uznałem, że najlepiej podane warunki będzie spełniać wynik działania którejś z wyszukiwarek internetowych. Wybrałem serwis Google (http://www.google.com), w którym szukałem stron zawierających słowo ala. Google znalazł około 2 310 000 stron w Internecie zawierających tę frazę[*]. Stworzyłem dwa skrypty w języku interpretatora poleceń bash. Pierwszy z nich, o nazwie prepare_links, kolejno: Natomiast drugi skrypt, nazwany links2db, tworzy polecenia w języku SQL ("insert into ...") wstawiające adresy do tabeli Strona. Oba skrypty są przedstawione w dodatku B. W ten sposób stworzyłem bazę adresów stron zawierającą 10 tys. pozycji. Z bazy tej korzystałem przy wykonywaniu testów wydajnościowych systemu.

2 Czas sprawdzania stron WWW

Celem pierwszego z wykonanych przeze mnie testów było zmierzenie czasów sprawdzania stron WWW. Interesował mnie rozkład tych czasów oraz czas minimalny, średni i maksymalny. Wiedza ta jest przydatna między innymi przy szacowaniu obciążenia systemu oraz wyznaczaniu dopuszczalnego czasu sprawdzania (ang. timeout). Aby pomiar jak najbardziej odpowiadał rzeczywistości, strony powinny być sprawdzane po kolei, w jednym wątku. Aby móc zaobserwować faktyczny maksymalny czas sprawdzania stron, należało ustawić długi dopuszczalny czas sprawdzania. W tym teście wynosił on 5 minut. Jeżeli w ciągu tego czasu nie udało się ściągnąć całej strony (lub pierwszych 100 kilobajtów, jeśli jej rozmiar jest większy), system uznawał, że strona jest niedostępna.

Test polegał na sprawdzeniu 10 tys. stron WWW. Ich adresy zostały wygenerowane przy pomocy skryptów opisanych w punkcie 6.1. Było to pierwsze sprawdzanie tych stron, w bazie danych nie było informacji o ich dacie ostatniej modyfikacji, wielkości czy wyniku funkcji MD5. Oznacza to, że podczas sprawdzania ściągane były całe strony, a nie tylko nagłówki odpowiedzi HTTP.

W trakcie przeprowadzania testu udało się ściągnąć 9581 stron. W przypadku pozostałych 419 stron system nie mógł nawiązać połączenia z serwerem lub sprawdzany adres URL był błędny. Czas sprawdzania był mierzony z dokładnością do 1/1000 sekundy. Minimalny, średni i maksymalny czas ściągania i sprawdzania strony wyniosły odpowiednio 1.007, 3.365 i 71.942 sekundy. Ściągnięcie 89% stron zajęło mniej niż 5 sekund. Rozkład liczby tych stron, sprawdzonych w kolejnych dziesiątych sekundy, pokazany jest na rys. 6.1.

Rysunek 6.1: Czasy sprawdzania stron

Ponieważ 30 sekund wystarczyło na ściągnięcie 99% stron, a maksymalny czas sprawdzania wyniósł 72 sekundy, można przyjąć, iż odpowiednią wartością dopuszczalnego czasu sprawdzania jest 60 sekund. Należy pamiętać, że podczas testu tylko jeden wątek sprawdzał strony. W przypadku większej ich liczby należy odpowiednio wydłużyć dopuszczalny czas sprawdzania.

3 Liczba wątków w programie sprawdzającym strony

Kolejnym pytaniem, na które należy znaleźć odpowiedź, jest pytanie o liczbę wątków sprawdzających śledzone strony. Jaka liczba będzie najbardziej odpowiednia, jaka zapewni największą wydajność. Postanowiłem zmierzyć czas pracy systemu, w którym działa kolejno 1, 2, 3, 5, 10, 15, 20, 25, 30, 40, 50, 70, 100, 150 i 200 wątków. Mierzyłem czas sprawdzania tysiąca identycznych adresów URL. Dzięki temu, że w praktyce system sprawdzał na okrągło tę samą stronę, znajdującą się na serwerze WWW podłączonym bardzo szybkim łączem z programem sprawdzającym, na wyniki testu nie wpłynęły czynniki zewnętrzne (różnice w czasie ściągania różnych stron itp.). Dla danej liczby wątków pomiar powtarzałem 5 razy, aby do analizy wziąć wartość uśrednioną.

Rysunek 6.2: Czas sprawdzania stron w zależności od liczby wątków

Po przeprowadzeniu testu okazało się, że liczba wątków nie ma dużego wpływu na czas działania programu. Rysunek 6.2 przedstawia średnie czasy sprawdzania stron w zależności od liczby wątków. Jedyną wyraźną różnicę w czasie widać dla programu jednowątkowego -- działał on ok. 1/4 dłużej niż wynosiła średnia dla programów z większą liczbą wątków. Przy okazji jednak dało się zaobserwować niedoskonałości implementacyjne maszyny wirtualnej Java. Przy dużej liczbie wątków (powyżej 50) program sprawdzający strony od czasu do czasu przerywał swoje działanie. Po zbadaniu przyczyn okazało się, że jest to problem wykorzystywanej przeze mnie implementacji maszyny wirtualnej Java na platformie Linux. W szczególności przerywanie działania programu nie było spowodowane wyciekami pamięci czy błędnym korzystaniem z mechanizmu wątków.

Biorąc pod uwagę wyniki testu, jak również zauważone błędy implementacji maszyny wirtualnej Java, rozsądną liczbą wątków wydaje się być wartość pomiędzy 5 a 25. Ostatecznie w uruchomionym systemie śledzone strony są sprawdzane przez 20 wątków.

4 Migracja zadań pomiędzy węzłami

Trzeci z przeprowadzonych testów polegał na uruchomieniu systemu na dwóch węzłach: jednym w Polsce oraz jednym w Szwajcarii. Węzły te sprawdzały 1000 różnych stron WWW (sposób zdobycia ich adresów opisano w punkcie 6.1), z których połowa znajdowała się w domenie .pl. Początkowo sprawdzane strony WWW były losowo rozdzielone pomiędzy oba węzły. Celem testu było przekonanie się, czy i w jakim tempie zadania sprawdzenia stron w domenie .pl będą przenoszone na węzeł umieszczony w Polsce. Ciekawe też było, czy taki podział osiągnie stabilność. Aby umożliwić migrację zadań pomiędzy węzłami, serwer główny był uruchamiany 200 razy (a więc system pracował 200 pełnych cykli). Natomiast współczynnik "przenosin" (czyli liczba zadań, które w jednym cyklu system próbował przenieść na inny węzeł w stosunku do liczby wszystkich zadań) wynosił 10%. Oznacza to, że w każdym cyklu system przenosił 100 losowo wybranych stron na inny węzeł, a następnie porównywał czasy sprawdzania na starym i nowym węźle i utrwalał zmianę, jeśli była ona korzystna. Zmiana była uznawana przez system jako korzystna, gdy zysk czasowy wynosił co najmniej 15%. Prawdopodobieństwo, że jakaś strona nie zostanie próbnie przeniesiona na inny węzeł, jest praktycznie równe zeru (90%200 < 10-9). Aby zmniejszyć liczbę czynników wpływających na wyniki eksperymentu, zostały zablokowane inne powody przenoszenia zadań między węzłami (np. przenoszenie, gdy jeden z węzłów skończy już realizowanie swoich zadań, a drugi jeszcze pracuje).

Rysunek 6.3: Zmiany węzłów

Cienka linia na rysunku 6.3 łączy punkty przedstawiające liczbę korzystnych zmian przypisań zadań do węzłów w kolejnych cyklach. Gruba linia na wykresie to linia trendu. W pierwszym cyklu system dokonał 34 efektywne zmiany (na 100 zmian próbnych). Jak można było przypuszczać, liczba korzystnych zmian dokonywanych w następnych cyklach wyraźnie maleje. Od około 40. cyklu liczba zmian w każdym kolejnym cyklu nie przekracza 4. Średnia liczba zmian dla cykli od 31. do 40. wynosi 2.33, od 41. do 50. cyklu -- 1.4, od 51. do 60. -- 0.55, a dla cykli od 51. do 200. średnia ta osiąga wartość 0.67. Można więc przyjąć, że podział zadań w przeprowadzonym teście osiągnął stabilność po około 40-50 cyklach.

Podczas testu system dokonał w sumie 528 zmian przypisań zadań do węzłów. Niektóre zadania były przepisywane z jednego węzła na drugi więcej niż raz. W efekcie po 200 cyklach 346 zadań zostało przeniesionych na inny węzeł, a reszta pozostała na swych początkowych węzłach.

Po przeprowadzeniu testu zainteresowało mnie również, o ile szybciej zadania są wykonywane na efektywniejszych węzłach. Przypomnijmy, że zmiana była utrwalana, jeśli zysk w czasie realizacji zadania na nowym węźle w porównaniu do poprzedniego wynosił co najmniej 15%. W ostatnim cyklu czas sprawdzania wszystkich stron był równy 87% czasu sprawdzania w pierwszego cyklu -- oznacza to zysk rzędu 13%. Biorąc pod uwagę jedynie zadania, które zostały choć raz przeniesione na inny węzeł, zysk ten wyniósł 23%. Wynika z tego, iż przenoszenie pomiędzy węzłami zadań sprawdzania śledzonych stron ma wyraźny (choć nie kluczowy) wpływ na wydajność całego systemu. Przenoszenie zadań pomiędzy węzłami jest realizowane przez serwer główny, więc nie ma większego wpływu na czas pracy węzłów.

Sebastian Łopieński