Migracja na mocniejszy hosting lub skalowanie ich w poziomie to nie jedyne opcje zwiększenia wydajności serwera aplikacji webowej czy portalu internetowego. Innym rozwiązaniem, dużo prostszym i być może efektywnym kosztowo jest przeniesienie różnych części systemu do oddzielnych fizycznych serwerów (lub instancji VPS), instalując każdy rodzaj usługi na osobnej maszynie fizycznej.

Używając terminu usługa w tym kontekście mam na myśli poszczególne składowe stosu LAMP i inne usługi wspierające jego funkcjonowanie:

  • serwer WWW (na przykład Apache),
  • baza danych (na przykład MySQL),
  • przechowywalnię plików (serwer plików),
  • pamięć podręczną (na przykład Memcached),
  • usługę FTP.

Partycjonowanie funkcjonalne serwera to proces polegający na izolacji monolitycznej aplikacji webowej na zestaw oddzielnych części, które mogą być utrzymywane i w dalszym ciągu skalowane niezależnie.

Separacja poszczególnych składowych systemu jest szczególnym przypadkiem skalowania serwera – pozwala do pewnego stopnia równoważyć obciążenie i we wczesnym etapie ewolucji aplikacji daje przestrzeń do jej rozwoju relatywnie niskim kosztem.

Rysunek 1: Aplikacja utrzymywana na pojedynczym serwerze

W przypadku wykorzystywania jednego serwera jedna maszyna (której zasobem jest procesor, pamięć RAM i jakiś rodzaj dysku do przechowywania pamięci masowej) zajmuje się zarówno

  • interpretowaniem i wykonywaniem kodu PHP „w locie”,
  • pełną obsługą bazy danych (odczyt, zapis i aktualizację),
  • obsługą połączeń HTTP.

Przy małej ilości użytkowników, serwer może w ten sposób pracować a utrzymanie na jednej maszynie wszystkich usług jest swego rodzaju standardem ze względu na niższy koszt utrzymania jednej maszyny niż kilku. Co więcej, taka maszyna najczęściej i tak się nudzi, odwiedziny na poziomie tysiąca użytkowników dziennie nie są żadnym obciążeniem nawet dla najtańszych opcji VPS.

Sprawa ma się całkiem inaczej w przypadku zwiększonego ruchu i większej ilości danych jaką trzeba obsługiwać. Użytkownicy aplikacji internetowej mogą w tym samym czasie wykorzystywać różne funkcjonalności i pracować na współdzielonych lub całkiem odrębnych danych. To powoduje kosztowne przełączanie się kontekstu procesora oraz przydzielanie jego skończonych zasobów obliczeniowych pomiędzy konkurującymi ze sobą żądaniami użytkowników. Jeżeli ilość użytkowników przekracza możliwości systemu, przestaje on działać, ponieważ czas odpowiedzi jest znacznie wydłużony lub może dochodzić nawet do niewykonania się poszczególnych operacji, które uruchomił użytkownik. Czas TTFB ulega wydłużeniu, dostawca blokuje hosting ze względu na limity a jakość doświadczeń użytkowników spada.

Przeniesienie plików statycznych do serwera plików

Jeżeli aplikacja jest bombardowana zapytaniami HTTP a aplikacja zawiera wiele zasobów do odczytu, bardzo prostym rozwiązaniem jest wykorzystanie gotowych systemów do przechowywania danych lub zakup serwera plików. Według mojego doświadczenia i obliczeń zawsze tańsze i opłacalne długofalowo powinno być wykorzystanie usługi Simple Storage Service (w skrócie S3) od Amazona.

Rysunek 2: Architektura aplikacji po wydzieleniu plików do S3

W tym artykule opisałem jak zintegrować AWS S3 w aplikacji PHP. Wszelkie zapytania o zasoby będą kierowane do S3. Dzięki temu nasz główny serwer nie będzie musiał ich wysyłać. Bierze się to stąd, że zasoby stanowią duży odsetek wszystkich zapytań HTTP i jest to spora oszczędność.

Integracja z CDN

Jeżeli już wydzieliliśmy zasoby do S3, równie prostym rozwiązaniem jest serwowanie plików znajdujących się w S3 za pomocą usługi CDN CloudFront. Wykorzystanie CDN ma wiele zalet i z wykorzystaniem konsoli AWS ogranicza się do kilku kliknięć.

Rysunek 3: Architektura aplikacji z wykorzystaniem sieci CDN

Bodźcem do tej modyfikacji jest też chęć zapewnienia szybkiego pobierania multimediów i plików statycznych dla użytkowników łączących się z innych kontynentów. Jak wspomniano w artykule dotyczącym sieci CDN – Content Delivery Network, sieć taka za pomocą optymalizacji drogi połączenia obniża czas dostępu do danych oraz odciąża serwer źródłowy. Koszt transferu z sieci CDN jest tańszy od transferu z usługi S3. Wykorzystując fakt, że transfer danych z usługi Amazon S3 do usługi Amazon CloudFront jest bezpłatny, automatycznie obniża się w ten sposób koszt transferu, który ma największy udział w wydatkach związanych z usługami AWS. Koszt będzie oczywiście mniejszy, jeżeli plik pobrane przez CDN będą przechowywanie w pamięci podręcznej HTTP zgodnie z ustawionym nagłówkiem CacheControl.

W tym momencie warto zadbać o to aby posługiwać się własną sub-domeną w przypadku korzystania z sieci CDN. Ma to wiele zalet:

  • posiadamy pełny dostęp do ustawień domeny,
  • posiadanie słów kluczowych lub nazwy marki serwisu jest korzystne z punktu widzenia SEO i UX,
  • możemy przełączać dostawcę CDN bez konieczności ponownych modyfikacji adresów.

O tym jak połączyć CloudFront z własnym kubłem S3 i zintegrować z nim własną domenę, pisałem przewodnik – własna domena w AWS CloudFront.

Baza danych na osobnym serwerze

Zakładając, że problem występuje nawet wtedy kiedy aplikacja korzysta już z pamięci podręcznej, drugim elementem, który warto oddzielić od naszej głównej maszyny będzie najczęściej baza danych. Problem ten występuje w aplikacjach, w których często zapisujemy lub aktualizujemy i odczytujemy dane. Częste zapisy inwalidują pamieć podręczną i baza wymaga więcej zasobów najczęściej pamięci RAM. Przykładowo, taki MySQL w przypadku braku pamięci fizycznej zaczyna korzystać z dyskowego pliku wymiany co może się przełożyć na oznaki nieefektywnych operacji wejścia-wyjścia. Aplikacja działa wolniej bo danych jest więcej a procesor wykonuje coraz więcej zróżnicowanych operacji. Rozwiązaniem jest optymalizacja bazy danych MySQL i wydzielenie bazy danych do osobnego serwera.

Rysunek 4: Architektura aplikacji po oddelegowaniu bazy danych na osobny serwer.

Bazę danych można teraz niezależnie skalować z wykorzystaniem sprawdzonych technik ich skalowania czyli np. replikacji baz danych lub będzie można ją podmienić z usługą DBaaS typu Amazon RDS (Aurora, MySQL) lub inne rozwiązanie zarządzanej bazy danych, które będzie kompatybilne z MySQL.

Memcached na niezależnej maszynie

Kolejnym krokiem po tak przeprowadzonej separacji poszczególnych elementów architektury na osobne maszyny fizyczne lub logiczne, może być wykorzystanie osobnej warstwy pamięci podręcznej Memcached. Może być bezpośrednio zintegrowana z bazą danych lub działać niezależnie jako osobna warstwa która może odciążać serwer PHP z wykonywania ponownie tych samych obliczeń lub generowania widoków.

Rysunek 5: Architektura aplikacji po dodaniu serwera pamięci podręcznej.

W myśl idei partycjonowania funkcjonalnego zainstalowano Memcached na kolejnej maszynie VPS – identycznej, która posłużyła w przypadku osobnego serwera bazy MySQL. Instalacja Memcached w aplikacji PHP podobnie jak w przypadku serwera MySQL sprowadza się do zainstalowania oprogramowania oraz edycji pliku konfiguracyjnego w celu umożliwienia połączenia się z zewnętrzną maszyną.

Wybór centrum danych a opóźnienia

Warto zadbać, aby poszczególne elementy architektury znajdowały się w tym samym centrum danych jednego dostawcy. Samo opóźnienie sieciowe w przypadku dwukierunkowego połączenia z bazą danych jest mocno odczuwalne. Korzystanie z Memcached, które jest zainstalowane powiedzmy we Frankfurcie, na Warszawskim serwerze zniweczy zysk czasowy. Sygnały nie dochodzą w zerowym czasie a pamiętajmy, że pomiędzy tymi elementami komunikacja odbywa się w dwóch kierunkach. Najpierw jest żądanie a potem odpowiedź.

Z tego powodu, jeżeli chcesz wykorzystać bazy danych Amazon RDS, zainteresuj się instancjami EC2 w tym samym datacenter. Próba łączenia serwera z OVH z baza danych w AWS skończy się na tym, że wszystko będzie działać… ale wolniej. Stack Overflow jest zalany poradami dotyczącymi skrócenia takich opóźnień, które jednym działają a innym nie. Wystarczy się pogodzić z tym, że fizyki nie pokonamy.

Podsumowanie

Partycjonowanie funkcjonalne serwera to dobry sposób do rozłożenia obciążenia na wiele maszyn, które nie wymaga skomplikowanych zmian w kodzie apliakcji. Powstałe elementy architektury można teraz pionowo lub poziomo skalować. Jest to powszechna konfiguracja aplikacji, które niski koszt utrzymania godzą z obsługą wielu użytkowników lub utrzymania dużego wolumenu danych.

Takie architektury mogą się też sprawdzić przy oferowaniu własnych usług hostingowych, bo są bardziej elastyczne. Większy klient z bardziej popularną stroną czy sklepem może być z łatwością przeniesiony na osobny serwer WWW lub osobną bazę danych (jeżeli generuje jej znaczne obciążenie). Wiedza o tym jak rozdzielić poszczególne usługi na osobnym serwerze przyda się także w tworzeniu architektur z wykorzystaniem gotowych infrastruktur Cloud.

Źródła

Henderson C. Building Scalable Web Sites. Building, Scaling, and Optimizing the Next Generation of Web Applications, Helion 2006.

Ejsmont A. Web Scalability for Startup Engineers, McGraw-Hill Education, New York, 2015.

http://highscalability.com/

Oceń artykuł na temat: Partycjonowanie serwera i izolacja serwisów
Średnia : 4.8 , Maksymalnie : 5 , Głosów : 16