sobota, 25 sierpnia 2012

RaspberryPi jako domowy serwer WWW - test wydajności (cz.2: Raspbian)

Po kilku godzinach poświęconych na doprowadzenie świeżo pobranego Raspbiana do stanu używalności - czyli po doinstalowaniu niezbędnych pakietów oprogramowania i skonfigurowaniu sobie środowiska pracy - przystąpiłem do testów serwerów WWW. Zasady testowania były podobne, jak za poprzednim razem, jednak konfiguracja platformy nginx + PHP trochę się zmieniła. Otóż jak pisałem wczoraj na twitterze i G+, repozytoria Raspbiana są bogatsze, niż Debiana Squeeze - przynajmniej o php5-fpm (FastCGI Process Manager) oraz node.js (w wersji 0.6.19 - nie najnowsza, ale w zupełności wystarczy). W poprzednim rozwiązaniu nginx współpracował z PHP poprzez FastCGI za pośrednictwem "rozpylacza" spawn_fcgi, który skonfigurowałem do odpalania maksymalnie trzech procesów php5-cgi. W nowszym rozwiązaniu mamy już możliwość zainstalowania efektywnego "rozpylacza" w postaci właśnie PHP-FPM, który - przynajmniej w założeniach - powinien działać adaptatywnie, czyli odpalać odpowiednią liczbę procesów php w zależności od potrzeb. Podczas testów uruchamiane było maksymalnie 5 procesów, więc istniała szansa, że - pomijając oczekiwane przyspieszenie ze względu na optymalizację platformy systemowej dla malinowego arma - serwer będzie działał sprawniej.
Żeby już nie męczyć Was (i siebie ;-)) wykresami, przedstawię tylko uśrednione wyniki testów. Przy okazji, podjąłem próbę wykonania testu na 3000 żądań po 300 równolegle - o ile nginx się parę razy zaksztusił, o tyle aplikacja node.js śmigała, jakby nic nigdy się nie stało. Oto więc wyniki:

Test na 1000 żądań po 100 równolegle
nginx:
Średnia liczba obsłużonych żądań na sekundę: 125,451 (maks. 152,21)
Średni czas obsługi żądania: 8,201 ms (min. 6,57 ms)
node.js:
Średnia liczba obsłużonych żądań na sekundę: 186,865 (maks. 188.71)
Średni czas obsługi żądania: 5,351 ms (min. 5,299 ms)

Test na 2000 żądań po 200 równolegle
nginx:
Średnia liczba obsłużonych żądań na sekundę: 143,411 (maks. 163.25)
Średni czas obsługi żądania: 7,05 ms (min. 6,126 ms)
node.js:
Średnia liczba obsłużonych żądań na sekundę: 187,771 (maks. 189.18)
Średni czas obsługi żądania: 5,326 ms (min. 5,286 ms)

Test na 3000 żądań po3100 równolegle
nginx: /dane z 7 ukończonych prób na 10 wykonanych/
Średnia liczba obsłużonych żądań na sekundę: 144,749 (maks. 154,15)
Średni czas obsługi żądania: 6,923 ms (min. 6,487 ms)
node.js:
Średnia liczba obsłużonych żądań na sekundę: 185,165 (maks. 187.19)
Średni czas obsługi żądania: 5,403 ms (min. 5,342 ms)

Wyniki są interesujące. Przede wszystkim moją uwagę zwróciło nierówne działanie nginksa, szczególnie podczas pierwszego testu (1000/100) - mocno zróżnicowane osiągi spowodowały dosyć słabe wartości średnie. Przy okazji wyszło, że nginx lepiej (sprawniej) działa przy większej liczbie żądań w danym czasie - byłby to bez mała serwer idealny (gdyby nie node.js ;))! Niestety, dane z trzeciego testu są w przypadku nginksa niekompletne - serwer zaczął "niewyrabiać" i trzy próby zakończyły się niepowodzeniem, ale próby udane świadczą o tym, że nginx ma możliwość utrzymania stałej wydajności nawet przy większym obciążeniu.
Node.js, jak wynika z testów, działa niczym przysłowiowy przecinak - wyniki poszczególnych serii (prób) nie różnią się specjalnie od siebie, a spadek wydajności przy dużym obciążeniu żądaniami jest nadal pomijalny. Oczywiście znów się okazuje, że node.js działa szybciej, niż nginx + PHP.
W poprzednich testach, na Debianie Squeeze, nginx osiągnął wartości średnie liczby obsłużonych żądań i czasu obsługi jednego żądania odpowiednio 152,487 i 6,56 ms dla testu "1000/100" oraz 135,739 i 7,378 ms dla testu "2000/200". Oznacza to, że w systemie Raspbian połączenie nginx i PHP działa sprawniej przy dużym obciążeniu - i to jest pozytywna informacja.
Jeśli zaś chodzi o node.js, to niestety wydajność w Raspbianie spadła w stosunku do tego, co zaobserwowałem w poprzedniej wersji systemu. W starym Squeeze node.js obsługiwał średnio 213 - 216 żądań na sekundę, a czas obsługi jednego żądania nie przekraczał 4,7 ms. Może to być winą sposobu przygotowania prekompilowanego node'a (dostępnego w repozytoriach systemu) - na Debianie dysponowałem binarkami własnoręcznie skompilowanymi, all-in-one, nie odwołującymi się do współdzielonych bibliotek (oczywiście poza niezbędnymi, systemowymi) itd.
Podsumowując - krótko - w Raspbianie, jeśli chodzi o serwery WWW, szału nie ma, choć nginx i PHP zdają się być tutaj dość stabilną rodziną. Cały czas jednak "oko Saurona" powinno być skierowane na Node.js - to na pewno jest właśnie TA platforma, która będzie rządziła na takich niewielkich komputerkach starających się być serwerami WWW.

piątek, 24 sierpnia 2012

RaspberryPi jako domowy serwer WWW - test wydajności (cz.1: Debian Squeeze)

W poprzednim wpisie na temat Raspberry Pi przedstawiłem sposób przekształcenia popularnej Maliny w domowy serwer WWW. Wykorzystałem nginksa, ponieważ jest lżejszy od apache, głównie dzięki  (ciągle jeszcze) nowatorskiej metodzie obsługi żądań, pozwalającej zaoszczędzić cenne zasoby skromnego systemu komputerowego, jakim niewątpliwie jest Raspberry Pi. Do tego oczywiście PHP5 i interfejs FastCGI, MySQL i SQLite. MySQL w wersji dostępnej w ramach dystrybucji Debian Squeeeze okazał się "odrobinę" za ciężki dla RPi, dlatego też, o ile to tylko możliwe, powinno się korzystać z SQLite lub innego, lekkiego rozwiązania - może któraś z NoSQL? Ale to już temat na osobny artykuł (NoSQL to nie moja działka) - wróćmy zatem do samego serwera webowego.
Bardzo ważna jest wydajność serwera WWW, rozumiana tutaj jako jego zdolność do sprawnego obsłużenia pewnej liczby żądań w jednostce czasu. Owszem, serwer domowy będzie obsługiwał co najwyżej kilka żądań w danym momencie, ale chodzi o sprawdzenie, jakim zapasem cierpliwości powinien dysponować użytkownik korzystający z świadczonych przez ten serwer usług.
Testy, o których mowa w tytule artykułu, polegały na sprawdzeniu za pomocą popularnego programu ab (Apache HTTP server benchmarking tool), jak serwer nginx, dostarczający prostą, napisaną w PHP aplikację zwracającą bieżącą datę i godzinę, radzi sobie z nawałem żądań.
Kod aplikacji testowej w PHP raczej nie powinien nikogo zaskoczyć:


Dla porównania przygotowałem aplikację sieciową zwracającą takie same informacje, napisaną w JavaScripcie dla Node.js:


Chodziło mi generalnie o to, żeby przeprowadzić podobne zestawienie, jak to miało miejsce w przypadku mojego - poświęconego właśnie Node.js - wystąpienia podczas 35. spotkania ŚRGM i PLSSUG w Katowicach.
W czasie testów zarówno nginx, jak i aplikacja Node.js, były uruchomione (działały "równolegle", nasłuchując na dwóch oddzielnych portach) i atakowane strumieniami żądań na przemian, za pomocą prostego skryptu (tutaj w wersji drugiej - poniżej wyjaśnienie):


Najpierw przeprowadziłem szybki test, polegający dziesięciokrotnym wysłaniu do każdego z serwerów po 1000 żądań, w porcjach po 100 żądań w tym samym czasie  (równolegle). Drugi test wyglądał podobnie z tym, że zwiększyłem liczbę żądań dwukrotnie - zarówno ogólną, jak i liczbę żądań wysyłanych równolegle. Przy większych liczbach żądań niż te, których użyłem w testach, Malina zaczynała się ksztusić; nie chciałem jednak szukać wartości progowych metodą prób i błędów, biorąc pod uwagę wiele czynników wpływających na wahania obciążenia komputera w danym momencie - i tak musiałbym przyjąć pewne wartości "bezpieczne".
Wyniki testów przedstawione zostały na wykresach, do których przejrzenia zachęcam (tutaj, żeby nie przesadzać z długością posta, tylko cztery najważniejsze wykresy, resztę można znaleźć w specjalnie przygotowanym "albumie").

Wykres 1: zestawienie liczby obsłużonych żądań na sekundę dla 10 prób (część pierwsza testu - 1000 żądań po 100 równolegle).

Wykres 2: zestawienie liczby obsłużonych żądań na sekundę dla 10 prób (część druga testu - 2000 żądań po 200 równolegle).

Wykres 3: średni czas obsługi żądania w przypadku obu serwerów - dla 10 prób (część pierwsza testu - 1000 żądań po 100 równolegle).

Wykres 4: średni czas obsługi żądania w przypadku obu serwerów - dla 10 prób (część druga testu - 2000 żądań po 200 równolegle).

Dla porównania można sprawdzić, jak wyglądały wyniki testów apache i Node.js w przypadku zwykłego, średniej klasy peceta - proszę przejść do slajdów nr 14 i 15 w prezentacji ze wspomnianego wcześniej spotkania.
Testy malinowego serwera WWW przeprowadziłem jeszcze na poprzednim, zalecanym dla RaspberryPi systemie Debian Squeeze, dlatego też wydaje mi się, biorąc pod uwagę to, co zaprezentował w swoim blogu Przemek Rumik (a co sprawdziłem osobiście na owym Debianie - wyszły wyniki słabsze, niż u Przemka), że Raspbian, zoptymalizowany dla RPi, pozwoli osiągnąć dużo lepsze rezultaty. Wkrótce powtórzę moje testy (i testy Przemka) na nowej, zoptymalizowanej dystrybucji Debiana.
Pora na kilka wniosków...
Proszę zwrócić uwagę, że nawet na tak mało wydajnym komputerze istnieje szansa, że siły i środki zainwestowane w zgłębienie wiedzy na temat tworzenia aplikacji sieciowych w Node.js mogą się zwrócić z nawiązką (spadek wydajności aplikacji Node.js przy podwojeniu intensywności testów był niewielki, prawie pomijalny). Trzeba tylko sprawdzić, czy uda się na RPi sensownie wdrożyć jakąś konkretną aplikację WWW (ciągle mamy wąskie gardło w postaci storage'u - karta SD, "coś" na USB lub poprzez moduł dla GPIO, o ile to ostatnie rozwiązanie istnieje). Próby z AjaXplorerem czy phpMyAdminem pokazały, że nie jest wesoło pod względem wydajności. No ale to był nginx (wcześniej - o zgrozo - apache; na Google+ prezentowałem screeny przedstawiające stan wolnej pamięci RPi, gdy strony serwował apacz; przejście na nginx było koniecznością i stanowiło dużą ulgę dla zasobów Maliny) i PHP5 poprzez FastCGI - może Node da radę "bardziej"?

Parę linków, które mogą się przydać: