Niedawno pisałem, że przeniosłem stronę Webinsider.pl z DigitalOcean (ale nadal polecam) na VPS w HitMe. Oczywiście przy takiej przeprowadzce wsparłem się m.in. transferem plików/danych między serwerami z wykorzystaniem SSH, i wprawdzie w teorii można w ten sposób spróbować przenieść cały system z jednej maszyny na drugą, to raczej dotyczy to sytuacji, gdy obie maszyny są jak najbardziej zbliżone pod względem konfiguracji (np. z Raspberry Pi na drugą Raspberry Pi), dlatego zazwyczaj w ten sposób kopiuje tylko niektóre katalogi (np. strony internetowe, katalogi domowe), a resztę (np. zabezpieczenia, webserwer) instaluje i konfiguruje od podstaw – przy dobrej organizacji (i procedurach) nie zajmuje to aż tak dużo czasu, a przy okazji jest okazja przypomnieć sobie co nieco. Czasem w takich momentach pojawia mi się też pomysł na nowy wpis/poradnik – i tak było i tym razem, bo o ile o PHP-FPM i PHP Pools pisałem nawet niedawno, to jeszcze nie poruszałem tematu związanego z trybem pracy menedżera procesów PHP, a jest to dość ciekawe zagadnienie, które w wielu poradnikach sprowadza się zazwyczaj do domyślnego trybu pracy, który nie zawsze jest najlepszy…

Menedżer procesów PHP-FPM (process manager)

Wprawdzie w większości przypadków domyślne ustawienie będzie się pewnie sprawdzało całkiem nieźle, to jednak warto wiedzieć, jak można zarządzać procesami PHP na serwerze, choćby w przypadku gdy na naszej stronie zwiększy się znacznie ruch, czy zacznie brakować pamięci lub czasu/mocy procesora.

Przykładowym błędem związanym z tym tematem, jaki możecie spotkać w logach usługi PHP (/var/log/php5-fpm.log) będzie np.:

[DATA GODZINA] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

Jest to dość częsty błąd na stronach z trochę większym ruchem niż „kilak(set) osób dziennie” i – nie wdając się zbytnio w szczegóły – oznacza tyle, że trzeba zwiększyć ilość procesów PHP (PHP-FPM), jakie mogą w danej chwili pracować (w przypadku cytowanego błędu zostawiłem wartość domyślną, czyli 5).

Maksymalna ilość procesów

Oczywiście w tym przypadku najprościej zwiększyć maksymalną procesów PHP, jaka może działać w tym samym czasie, poprzez modyfikację tylko jednego parametru – pm.max_children:

sudo nano /etc/php5/fpm/pool.d/www.conf

I zmieniamy:

pm.max_children = 5

np. na 10:

pm.max_children = 10

Na koniec wystarczy zrestartować usługę PHP:

sudo service php5-fpm restart

Po co ustawiać w ciemno, jak można policzyć

Oczywiście możecie mieć wątpliwości, jaką wartość ustawić by było dobrze – nie ma na to jednoznacznej odpowiedzi, ja zazwyczaj stopniowo zwiększam liczbę (ilość ;-)) procesów, aż błąd zniknie, a do tego dodaje mały zapas.

Oczywiście nie jest to tak, ze wartość/liczbę możemy zwiększać baz ograniczeń, bo każdy proces to nie tylko dodatkowe obciążenie procesora, ale – a może przede wszystkim – wykorzystanie kolejnym megabajtów pamięci RAM, której zazwyczaj nigdy nie jest za dużo… ;-)

Na obecnym serwerze (XEN2G) mam 2 GB pamięci RAM (+ 4 GB pamięci SWAP, ale tego typu pamięci sugeruję nie brać pod uwagę w wyliczeniach, chyba że nie macie wyjścia), a więc jest to 2048 MB.

Średnio jeden proces (jedno wystąpienie) PHP u mnie to jakieś 3-3,3% pamięci, czyli ok 61-62 MB. Na wszelki wypadek dajmy z zapasem, więc powiedzmy, że będzie to 70 MB (ale nie kierujcie się tutaj moim przypadkiem, sprawdzicie, jak to wygląda u Was).

Tak więc 2048 MB dzielimy na 70, co nam daje ~29, ale trzeba pamiętać, że z pamięci RAM korzystają również inne usługi, w tym choćby system.

Dlatego lepiej sprawdzić ilość wolnej pamięci RAM podczas normalnej pracy serwera i podzielić ją przez 70-75. Otrzymaną wartość warto jeszcze trochę odchudzić i mniej więcej o to, co zostanie, możemy zwiększyć liczbę procesów PHP (pm.max_children).

Zarządzanie procesami (instancjami) PHP-FPM

Gdy już wiemy jaką wartość maksymalnie możemy ustawić (przynajmniej teoretycznie), to warto poznać jeszcze tryby pracy menedżera procesów PHP, gdyż nie w każdym przypadku domyślny tryb będzie najlepszy.

Static

Celowo nie zaczynam od domyślnie aktywnego trybu (dynamic), a od trybu static, gdyż na nim będzie mi chyba najłatwiej wyjaśnić, o co chodzi, a zarazem będzie to dobry punkt wyjścia dla pozostałych – już bardziej skomplikowanych w swojej zasadzie działania – trybów.

W tym trybie – jak sama nazwa wskazuje – ustalamy na sztywno liczbę procesów, która będzie cały czas działać w systemie, nawet jak nie będzie w danej chwili takiej potrzeby.

Ustawiamy właściwie tylko jeden parametr – ilość aktywnych procesów:

sudo nano /etc/php5/fpm/pool.d/www.conf

pm = static
pm.max_children = 5

Pewnie niektórym ten tryb już się spodobał, bo ilość dodatkowych ustawień jest równa zeru, ale ten tryb ma też swoje wady – niezależnie od ruchu na stronie, niezależnie od potrzeb zawsze w systemie będzie działać określona liczba procesów, tym samym stale zajmując dla siebie pamięć RAM (70-75 MB na każdą instancję).

Na plus – oprócz prostej konfiguracji – można zaliczyć również to, że w przypadku mocno obciążonych serwerów/stron z dużym ruchem może to być najbardziej wydajny tryb, gdyż zadeklarowana liczba procesów/instancji cały czas czeka w pogotowiu do działania…

Ondemand

Drugim trybem pracy, który chciałbym przedstawić jest ondemand – moim zdaniem dość niedoceniany tryb (rzadko pojawia się w poradnikach), a zwłaszcza w przypadku gdy korzystamy z niezależnych gniazd dla poszczególnych stron, na których dodatkowo ruch jest relatywnie niewielki, może to być prawdziwe wybawienie dla serwera, dzięki czemu możemy oszczędzić sporo pamięci RAM (a ew. różnica w wydajności względem trybu static powinna sprowadzać się właściwie tylko do czasu potrzebnego na wystartowanie potrzebnego procesu, czyli jakieś milisekundy).

Można powiedzieć, że jest to w pewnym sensie przeciwieństwo trybu static, bo w trybie ondemand ustawiamy maksymalną liczbę procesów, ale będą one uruchamiane tylko w razie potrzeby, a po ustawionym czasie bezczynności zabijane, zwalniając tym samym zasoby.

Parametrów do ustawienia nie ma dużo więcej – dochodzi czas bezczynności:

sudo nano /etc/php5/fpm/pool.d/www.conf

pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s

W powyższej przykładowej konfiguracji mamy maksymalnie 5 procesów, które będą zabijane po 10 sekundach bezczynności.

Dynamic

No i tym sposobem dotarliśmy do trzeciego i ostatniego trybu – dynamic, czyli dynamicznego zarządzania procesami.

Jest to tryb, który pewnie spotkacie w konfiguracji większości serwerów, co wynika nie tylko z tego, że jest on domyślnie aktywny, ale również z tego, że jest to chyba najbardziej uniwersalny tryb – z jednej strony procesy są tworzone i zabijane wedle potrzeb (ondemand), ale z drugiej strony możemy ustawić minimalną liczbę procesów oczekujących w stanie bezczynności na działanie (static).

Przykładowa konfiguracja usługi PHP wygląda np. tak:

sudo nano /etc/php5/fpm/pool.d/www.conf

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Jak widać, jest tu sporo więcej parametrów do ustalenia niż w pierwszych 2 trybach, ale chyba nadal nie jest to nic szczególnie skomplikowanego, zwłaszcza że jak wspomniałem – ten tryb jest aktywny domyślnie, a więc wstępne ustawienia macie gotowe.

Mamy tu dynamiczne zarządzanie procesami (pm = dynamic), których maksymalnie będzie 5, z tego 2 starują od razu, wraz ze startem webserwera/usługi PHP. W stanie oczekiwania (bez zadań) może być minimum 1 proces, ale nie więcej niż 3.

Wyciek pamięci

Skoro już jesteśmy przy tych ustawieniach, to jest jeszcze jedne parametr – właściwie uniwersalny, bo ma zastosowanie dla każdego z opisanych powyżej trybów, a może przeciwdziałać tzw. wyciekowi pamięci, jaki może się przydarzyć np. jakimś zewnętrznym modułom, a będzie się objawiał brakiem zwalniania wykorzystanej wcześniej pamięci, co w efekcie może doprowadzić nawet do wyczerpania pamięci RAM w naszym serwerze.

W tym celu wystarczy ustawić automatyczne resetowanie procesu PHP po zadeklarowanej liczbie aktywności, np. 500:

sudo nano /etc/php5/fpm/pool.d/www.conf

pm.max_requests = 500

I choć jak napiąłem, jest to uniwersalne ustawienie, to wydaje mi się szczególnie przydatne w przypadku korzystania z trybu static, gdzie poza restartem serwera lub usługi PHP procesy działają nieprzerwanie.

(!) Zgłoś błąd na stronie
Pomogłem? To może postawisz mi wirtualną kawę?
LUTy dla D-Cinelike (DJI Mini 3 Pro, DJI Avata, OSMO Pocket) od MiniFly
Wdrożenie Omnibusa w sklepie na WooCommerce
Jak (legalnie) latać dronem w Kategorii Otwartej
Patryk