Skalowalność aplikacji webowych

Najpopularniejszym językiem aplikacji webowych jest PHP. Jednak przy dużym obciążeniu pojawiają się problemy z ich wydajnością.

Podstawową zaletą PHP, najpopularniejszego na świecie języka programowania dla aplikacji Web, jest możliwość bardzo szybkiego i taniego utworzenia oprogramowania zgodnie z potrzebami. Niestety, domyślne środowisko LAMP (Linux, Apache, MySQL, PHP) nie jest wystarczająco skalowalne i nie poradzi sobie przy dużym obciążeniu.

Część deweloperów w ogóle nie dba o utrzymanie aplikacji. Ich oprogramowanie nie będzie działało powyżej pewnej liczby użytkowników. Za przykład niech posłuży aplikacja marketingowa obejmująca program lojalnościowy, w którym punkty za kupione przedmioty można wymienić na wirtualne opcje w . Aplikacja została napisana w PHP i korzysta z bazy danych Oracle. Problemy wydajnościowe zaczęły się pojawiać, gdy liczba użytkowników przekroczyła kilka milionów.

Jeśli korzystająca z aplikacji firma ma klastry webowe i bazodanowe składające się z wielu węzłów, skalowalność pozioma rozwiązuje problem. Przy rozproszonym przetwarzaniu w PHP i stosowaniu w tzw. back-end baz danych takich jak Oracle, osiągnięcie oczekiwanej skalowalności przetwarzania transakcji jest zbyt kosztowne. Wąskim gardłem jest sama konstrukcja PHP, która uniemożliwia połączenie struktury skalowalnej poziomo (klaster webowy) z centralizowaną bazą danych, taką jak np. Oracle.

Runtime PHP nie spełnia wymagań

Najczęściej stosowanym środowiskiem pracy PHP jest serwer webowy Apache w trybie prefork. W tym trybie serwer uruchamia zestaw podprocesów, które obsługują równoległe żądania. Gdy zestawi się tę równoległą charakterystykę pracy z działaniem tradycyjnej relacyjnej bazy danych, takiej jak MySQL, PostgreSQL czy Oracle, widać, że niezbędne są osobne połączenia do bazy danych dla każdego z procesów. Wynika to stąd, że zestawienie połączeń we wspólnej puli wymaga współdzielonego obszaru pamięci, a tym środowisko pracy PHP wewnątrz wielu procesów Apache nie dysponuje.

Natywne wątki mają współdzielony obszar pamięci, jako część swojego głównego procesu. Tej możliwości nie mają podprocesy, chyba że wykorzysta się specyficzny obszar systemowy nazywany pamięcią współdzieloną. Obecna wersja modułu prefork nie obsługuje tej opcji. Współdzielona pamięć działa wolniej. Chociaż istnieje możliwość uruchomienia PHP z obsługą natywnych wątków (nazywana worker mode), to zależy ona od możliwości wielowątkowej pracy (thread safe) wykorzystywanych modułów.

Od aplikacji do bazy

Równoległy model pracy PHP ma poważny wpływ na skalowalność całego rozwiązania przy pracy z tradycyjną bazą danych RDBM. Chociaż do baz takich jak MySQL czy Oracle można otworzyć tysiące niewspółdzielonych, równoległych połączeń, będą one miały wysoce negatywny wpływ na liczbę obsługiwanych równoczesnych żądań.

W pracy typowej aplikacji webowej występują długie okresy, gdy nie przejawia ona żadnej interakcji z bazą danych, a zatem inne żądanie mogłoby współdzielić to samo połączenie do bazy danych. Wymaga to utworzenia puli połączeń. Ponieważ model pracy PHP tego nie umożliwia, można albo utrzymywać nieaktywne połączenia na czas cyklu żądanie - odpowiedź, albo za każdym razem je otwierać i zamykać.

Problem z wielokrotnym otwieraniem i zamykaniem połączenia wiąże się z charakterystyką otwierania połączeń socketowych w systemie operacyjnym. Stos TCP posiada ochronę przed osieroconymi pakietami z poprzedniego połączenia, co wymaga pewnego opóźnienia przed ponownym otwarciem połączenia. Tak więc liczba połączeń w czasie jest ograniczona. To samo dotyczy motoru bazy danych po stronie serwera bazodanowego, który jednocześnie jest bardzo silnie obciążony. Gdyby analizować ruch, można zobaczyć bardzo wiele połączeń w stanie TIME_WAIT lub CLOSE_WAIT - a to oznacza właśnie oczekiwanie przed ponownym otwarciem socketu. Tymczasem w środowisku runtime, które umożliwia utworzenie puli współdzielonych połączeń, można zauważyć stałą liczbę połączeń w stanie ESTABLISHED (nawiązane).

Podział na serwery lub chmura i NoSQL

Aby aplikacje w PHP lepiej się skalowały, niezbędny jest logiczny podział danych w bazach na wiele maszyn. W praktyce oznacza to podzielenie klientów na różne bazy na podstawie wybranego klucza, co wiąże się ze wzrostem skomplikowania infrastruktury oraz samej aplikacji. Generuje także dodatkowe wydatki, jeśli baza danych back-end jest wydawana na kosztownej, komercyjnej licencji.

Dobrym środowiskiem do migracji klastra webowego jest wysoko skalowalna chmura obliczeniowa. Można wtedy też skorzystać z bazy skalowalnej w tym samym modelu co klaster webowy. Bazą taką jest NoSQL, która umożliwia efektywne współdzielenie danych między wieloma węzłami. Przy dobrym opracowaniu aplikacji korzystającej z NoSQL, można uzyskać skalowalność daleko wykraczającą poza możliwości typowych baz danych RDBMS w połączeniu z klastrem webowym PHP.

Ograniczenia wieku dziecięcego

Początkowo Linux nie obsługiwał wątków, a jedynie podprocesy. Systemy wywodzące się z Windows NT od dawna wspierały wątki, a zatem, teoretycznie, mogły działać znacznie sprawniej niż Linux. Niestety, w czasie gdy Microsoft prowadził badania nad wątkami, nikt nie wierzył w początkowe wyniki tych prac. Obecnie Linux bardzo sprawnie obsługuje wątki natywne, znacznie lepiej niż Windows. Nie wszystkie jednak aplikacje są napisane w ten sposób, by z tej możliwości skorzystać.