Architektura wydajnego stosu LEMP: Nginx, PHP-FPM, MariaDB i Redis – strojenie pod obciążenie produkcyjne
Poniższe opracowanie to kompleksowe kompendium strojenia stosu LEMP (Linux, Nginx, MariaDB/MySQL, PHP-FPM) pod obciążenie produkcyjne. Opisujemy kaskadę połączeń między warstwami serwera, precyzyjną kalkulację pamięci RAM dla każdego komponentu, konfigurację OPcache i keepalive, strategie buforowania Redis i fastcgi_cache oraz profesjonalne profilowanie wąskich gardeł za pomocą narzędzi takich jak strace, Performance Schema i Flamegraph.
Wprowadzenie do nowoczesnej architektury LEMP
Współczesne aplikacje internetowe, w tym zaawansowany hosting WordPress, wymagają środowiska zdolnego do błyskawicznego serwowania treści oraz odporności na nagłe skoki ruchu (tzw. "wykop effect"). Przez lata standardem branżowym był serwer Apache, wykorzystujący moduł mod_php, który wiązał proces interpretera PHP bezpośrednio z każdym żądaniem HTTP. Niestety, w warunkach produkcyjnych architektura ta prowadzi do szybkiego wysycenia pamięci RAM, jako że nawet serwowanie statycznych plików graficznych angażuje ciężkie, pamięciożerne procesy.
Odpowiedzią na ten problem jest stos LEMP (Linux, Nginx, MariaDB/MySQL, PHP-FPM). W tym modelu Nginx, działający często jako odwrócone proxy (reverse proxy), obsługuje tysiące jednoczesnych połączeń asynchronicznie, zużywając przy tym ułamek megabajta pamięci. Z kolei PHP-FPM (FastCGI Process Manager) działa jako całkowicie niezależny menedżer, utrzymujący w gotowości oddzielną pulę procesów roboczych (workerów), komunikując się z serwerem www wyłącznie przez gniazda unixowe lub porty TCP. Całość domyka baza relacyjna MariaDB oraz Redis pełniący rolę błyskawicznego magazynu struktur w pamięci.
Optymalizacja WordPress czy dowolnej innej aplikacji opartej na PHP w architekturze LEMP nie polega na ślepym zwiększaniu zasobów sprzętowych. Kluczem do stabilności jest precyzyjne matematyczne zestrojenie parametrów każdego z tych komponentów tak, aby współdziałały one niczym idealnie dopasowane koła zębate.
Sprzężenie zwrotne: Kaskada połączeń w architekturze LEMP
Najczęstszym błędem przy konfiguracji środowiska jest rozpatrywanie usług w izolacji. W rzeczywistości przepływ żądań tworzy ścisłą kaskadę, w której parametry poszczególnych warstw muszą ze sobą korespondować. Lejek ten można opisać następująco:
- Warstwa wejściowa (Nginx): Parametr
worker_connections(pomnożony przez liczbę rdzeni procesora, czyliworker_processes) definiuje, ile maksymalnie jednoczesnych połączeń TCP od klientów może obsłużyć serwer. W środowiskach produkcyjnych używa się tu wartości od1024do8192. - Warstwa logiki (PHP-FPM): Kiedy Nginx odbiera żądanie wymagające wykonania kodu PHP, przekazuje je do puli procesów określonej przez
pm.max_children. Jeśli Nginx przyjmie 2000 żądań, alepm.max_childrenwynosi zaledwie50, pozostałe 1950 żądań zostanie natychmiast wrzucone do kolejki oczekujących, co z punktu widzenia użytkownika objawi się jako drastyczne spowolnienie (lub ostatecznie wygeneruje błąd 502/504 Gateway Timeout). - Warstwa danych (MariaDB): Każdy pracujący potomek PHP może nawiązać połączenie z bazą danych. Jeżeli
pm.max_childrenzostanie bezrefleksyjnie ustawione na300, a parametr bazy MariaDBmax_connectionsna domyślne151, w momencie nagłego piku ruchu procesy PHP błyskawicznie wyczerpią pulę połączeń bazy danych, co poskutkuje krytycznymi błędami "Too many connections" po stronie aplikacji.
Aby zapobiec takim awariom, konfiguracja musi być świadoma: parametr max_connections w bazie MariaDB powinien zawsze być nieco większy (np. o 10-20% na potrzeby administracyjne) niż całkowity limit pm.max_children ze wszystkich działających pul PHP. Z kolei Nginx musi być w stanie utrzymać otwarte połączenia z klientami przez czas niezbędny do obsłużenia ich przez PHP-FPM.
Optymalizacja limitów jądra Linux (sysctl i ulimits)
Sprawnie działająca kaskada połączeń zależy w dużej mierze od tego, na co pozwala sam system operacyjny. Domyślny miękki limit (soft limit) otwartych plików w systemie Linux wynosi często zaledwie 1024. Serwer Nginx obsługujący wysoki ruch – gdzie każde połączenie zużywa deskryptory plików dla gniazd sieciowych i serwowanych plików statycznych – szybko ten limit wyczerpie, doprowadzając do odrzucania ruchu. Niezbędne jest dodanie dyrektywy worker_rlimit_nofile z wartością 65535 w konfiguracji Nginx oraz dostosowanie limitów systemowych w pliku limits.conf lub na poziomie konfiguracji systemd (parametr LimitNOFILE).
Należy również zadbać o odpowiednie strojenie TCP/IP. Warto rozszerzyć zakres lokalnych portów poprzez parametr net.ipv4.ip_local_port_range w usłudze sysctl oraz zwiększyć maksymalny rozmiar kolejki połączeń sieciowych poprzez net.core.netdev_max_backlog, co skutecznie zapobiega odrzucaniu pakietów podczas nagłych pików ruchu w serwisie.
Osobną uwagę zasługuje parametr net.core.somaxconn, który kontroluje maksymalną długość kolejki oczekujących połączeń TCP na poziomie wywołania systemowego listen(). W starszych jądrach Linux (poniżej 5.4) domyślna wartość wynosi zaledwie 128, co przy intensywnym ruchu powoduje odrzucanie połączeń jeszcze zanim trafią do Nginx. We współczesnych jądrach (5.4+) domyślna wartość została podniesiona do 4096, ale w środowiskach o bardzo dużym ruchu warto ją zwiększyć dalej (np. do 65535). Wartość ta musi być zsynchronizowana z parametrem backlog w dyrektywie listen konfiguracji Nginx – niższy z tych dwóch limitów staje się efektywnym wąskim gardłem.
Kalkulacja pamięci i konfiguracja w zależności od dostępnego RAM
Głównym ogranicznikiem na każdym serwerze LEMP jest pamięć operacyjna. System operacyjny, procesy Nginx, bufory MariaDB oraz dzieci PHP-FPM muszą zmieścić się w fizycznym RAM-ie, aby uniknąć użycia pamięci wymiany (SWAP), która natychmiastowo dławi wydajność.
Podstawowy wzór na obliczenie bezpiecznej ilości procesów potomnych PHP to:
pm.max_children = (Całkowity RAM − Rezerwa dla Systemu − Nginx − Redis − Bufory MariaDB) / Średni rozmiar procesu PHP
Średni rozmiar procesu można sprawdzić na działającym serwerze za pomocą polecenia odczytującego RSS (Resident Set Size) procesów php-fpm. W zależności od skomplikowania wtyczek, dla WordPressa zazwyczaj oscyluje on w granicach 40 do 80 MB.
Równie istotny jest wybór trybu menedżera procesów (pm) w konfiguracji puli PHP-FPM. Dostępne są trzy strategie: pm = static utrzymuje stałą, niezmienną liczbę procesów roboczych – zapewnia przewidywalne zużycie RAM i eliminuje narzut na tworzenie nowych procesów, co czyni go zalecanym trybem dla serwerów dedykowanych pod jedną aplikację. Tryb pm = dynamic skaluje liczbę workerów w zakresie od pm.min_spare_servers do pm.max_spare_servers, dostosowując się do bieżącego ruchu. Tryb pm = ondemand tworzy procesy dopiero po nadejściu żądania i usuwa je po okresie bezczynności (pm.process_idle_timeout) – oszczędza pamięć, ale dodaje opóźnienie przy pierwszym żądaniu po okresie ciszy. W środowiskach produkcyjnych z przewidywalnym ruchem tryb static zapewnia najniższe opóźnienia.
Oto przykładowe, bezpieczne rozkłady sił dla różnej wielkości serwerów:
1. Serwer wejściowy: 4 GB RAM (np. 2 vCPU)
Na tak niewielkim serwerze kluczem jest agresywne oszczędzanie pamięci. MariaDB nie może zaalokować gigantycznych buforów, a liczba jednoczesnych połączeń musi być ściśle limitowana.
- MariaDB:
innodb_buffer_pool_sizeustalamy na około1.5 GB(zajmując nieco ponad 1/3 dostępnego RAM). - Redis: Przydzielamy skromny limit na poziomie
256 MB(maxmemory). - PHP-FPM: Przyjmując średni rozmiar procesu na 50 MB, zostaje nam do dyspozycji około 1.5 GB na PHP. Bezpieczna wartość
pm.max_childrento 30. - Nginx:
worker_connectionsna poziomie2048, z silnym wsparciem pamięci podręcznej mikro-cache. - MariaDB:
max_connectionszabezpieczamy na poziomie60.
2. Serwer optymalny: 16 GB RAM (np. 4 do 8 vCPU)
Jest to tzw. "sweet spot" dla zaawansowanych portali i e-commerce. Mamy wystarczająco dużo zasobów, aby przenieść dużą część bazy danych do pamięci operacyjnej oraz obsłużyć spory ruch na żywo.
- MariaDB:
innodb_buffer_pool_sizeustawiamy na8 GB(połowa RAM). Baza zacznie działać niesamowicie szybko, omijając I/O dysku. - Redis: Rozszerzamy limit do
1 GB. - PHP-FPM: Mamy około 5 GB rezerwy na logikę aplikacji. Wartość
pm.max_childrenmożemy śmiało ustawić na 100. - Nginx:
worker_connectionsna poziomie4096lub8192. - MariaDB:
max_connectionsna poziomie150(zapas dla 100 procesów PHP oraz połączeń z innych usług).
3. Serwer korporacyjny: 32 GB RAM (np. 8 do 16 vCPU)
Środowisko przeznaczone dla olbrzymich sklepów i potężnych portali informacyjnych. Wymaga to ostrożnego dobrania puli początkowej PHP-FPM (pm.start_servers), aby uniknąć przeciążenia procesora podczas masowego uruchamiania nowych procesów.
- MariaDB:
innodb_buffer_pool_sizealokuje aż20 GB. - Redis: Zyskuje komfortowe
2 GBpamięci. - PHP-FPM: Ze strefy operacyjnej wyodrębniamy około 8 GB. Pozwala to na ustawienie
pm.max_childrenw przedziale 150 do 200 (zależnie od wagi skryptu). - Nginx:
worker_connectionsmoże zostać podbite do16384. - MariaDB:
max_connectionspodnosimy bezpiecznie do300.
Zaawansowane strojenie PHP OPcache oraz przeciwdziałanie wyciekom pamięci
Na ostateczną wydajność aplikacji ogromny wpływ ma samo zarządzanie wywołaniami wewnątrz interpretera. OPcache przechowuje prekompilowany kod bajtowy PHP bezpośrednio w pamięci RAM, co pozwala zwiększyć wydajność wykonywania skryptów od 2 do nawet 3 razy. Warunkiem jest poprawne skonfigurowanie parametrów – przede wszystkim odpowiednio wysokie wartości opcache.memory_consumption oraz opcache.max_accelerated_files.
Niezbędna jest również kontrola wycieków pamięci. W konfiguracji puli PHP-FPM należy bezwzględnie zdefiniować parametr pm.max_requests = 500. Powoduje on automatyczny i bezpieczny restart danego procesu roboczego (workera) po obsłużeniu równo 500 żądań. Ten mechanizm zapobiega stopniowemu "pożeraniu" cennej pamięci RAM przez wadliwie napisany kod aplikacji lub ciężkie, opasłe wtyczki.
W środowiskach produkcyjnych dodatkową optymalizację zapewnia ustawienie opcache.validate_timestamps = 0. Domyślnie OPcache co kilka sekund (zgodnie z parametrem opcache.revalidate_freq) sprawdza, czy pliki PHP na dysku uległy zmianie. Wyłączenie tej weryfikacji eliminuje zbędne operacje stat() przy każdym żądaniu – OPcache serwuje wyłącznie skompilowaną wersję kodu z pamięci. Kompromisem jest konieczność ręcznego przeładowania cache'u po wdrożeniu nowej wersji aplikacji, np. poprzez restart PHP-FPM lub wywołanie funkcji opcache_reset() w skrypcie deployu.
Optymalizacja połączeń keepalive między Nginx a PHP-FPM
Kolejnym wąskim gardłem, które należy zneutralizować, jest sama metoda komunikacji pomiędzy serwerem WWW a interpreterem. Przy komunikacji na tym samym fizycznym serwerze gniazda unixowe (Unix Sockets) są zawsze szybsze niż porty TCP. Należy jednak pamiętać, że Nginx domyślnie otwiera i zamyka nowe połączenie FastCGI przy każdym żądaniu. Konfigurując blok upstream w ustawieniach Nginx, warto stanowczo wdrożyć połączenia persistentne za pomocą dyrektywy keepalive 32. Taka zmiana pozwala systemowi na inteligentne, ponowne wykorzystanie już otwartych gniazd, co drastycznie redukuje potężny narzut procesora podczas procesów negocjacji i nawiązywania połączeń.
Parametryzacja MariaDB pod kątem dysków SSD/NVMe i wątków
Alokacja pamięci dla bazy danych nie kończy się na włączeniu dużej puli buforów (InnoDB Buffer Pool). Parametr max_connections nie alokuje pełnej pamięci przy rozruchu, ale wyznacza szczytowy, maksymalny footprint pamięciowy bazy. Każde nowe połączenie tworzy dedykowany wątek, który wymaga natychmiastowej alokacji rezerwy pamięci. Najistotniejszy składnik tej rezerwy to stos wątku, kontrolowany parametrem thread_stack.
Przy sprzętowej optymalizacji pod superszybkie dyski SSD, należy ustawić parametr innodb_flush_neighbors na wartość 0. Ustawienie to natychmiast wyłącza zbędne, systemowe grupowanie zapisu sąsiednich bloków (funkcja ta była przydatna w przeszłości, ale wyłącznie przy optymalizacji fizycznego ruchu głowicy w starych dyskach magnetycznych).
Należy postawić również na agresywne opróżnianie buforów w czasie rzeczywistym. Warto dostosować parametry innodb_io_capacity (podnosząc go na przykład do 10000) oraz innodb_io_capacity_max (nawet do 20000) idealnie do rzeczywistych możliwości sprzętowych użytych dysków SSD/NVMe. Zabieg ten pozwala silnikowi na wielokrotnie szybsze i płynniejsze zapisywanie tzw. brudnych stron z pamięci operacyjnej na dysk.
Parametrem, który często pozostaje niedostrojony, jest rozmiar pliku dziennika redo. W MariaDB do wersji 10.5 kontroluje go innodb_log_file_size (domyślnie 48 MB) w połączeniu z innodb_log_files_in_group. Zbyt mały dziennik wymusza częste operacje checkpoint – silnik musi wstrzymać zapisy, by zwolnić miejsce w logu, co drastycznie obniża przepustowość pod obciążeniem. Dla serwerów produkcyjnych zalecane jest ustawienie w przedziale 256 MB do 1 GB. W MariaDB 10.6+ parametry te zastąpiono pojedynczym innodb_redo_log_capacity, który definiuje łączny rozmiar całej przestrzeni dziennika redo.
Strategie pamięci podręcznej: Redis kontra fastcgi_cache
Brak inteligentnej strategii buforowania sprawi, że nawet najpotężniejszy serwer ostatecznie polegnie pod naporem zapytań PHP i SQL. Tu do gry wchodzą mechanizmy dostarczane przez Nginx oraz Redis, które ucinają drogę żądania na różnych etapach lejka.
Redis jako obiektowy cache (Object Cache)
Każde załadowanie zaawansowanej strony może wywołać od kilkudziesięciu do nawet kilkuset zapytań do bazy MariaDB. Zastosowanie Redisa jako magazynu obiektowego sprawia, że wyniki tych skomplikowanych zapytań SQL są trzymane w strukturach pamięci RAM (key-value). Gdy kolejny proces PHP potrzebuje tej samej porcji danych, pobiera ją bezpośrednio z Redisa z ułamkowym opóźnieniem, całkowicie omijając obciążającą procesor warstwę silnika InnoDB.
Kluczowe dla utrzymania stabilności w rozwiązaniach obiektowych jest perfekcyjne zarządzanie przepełnieniem cache'u. W konfiguracji serwera redis.conf absolutnie konieczne jest ustalenie granicznego parametru maxmemory, tak aby był on sztywno dostosowany do bezpiecznego budżetu RAM-u na hoście.
Oprócz tego należy zdefiniować politykę usuwania starych kluczy, wpisując maxmemory-policy allkeys-lru. Dzięki temu ustawieniu, po osiągnięciu granicznego limitu pamięci, Redis automatycznie usunie najrzadziej używane obiekty lub strony HTML, zamiast zwracać błędy zapisu (OOM) przy nowych nadchodzących żądaniach.
Gdy Redis pełni wyłącznie rolę cache'u (obiektowego lub full-page), należy również wyłączyć zapis na dysk. Domyślnie Redis periodycznie tworzy migawki RDB (snapshoty), co wymaga operacji fork() kopiującej całą przestrzeń adresową procesu. Na serwerze z dużym przydziałem pamięci dla Redisa (np. 2 GB) taki fork generuje zauważalne, cykliczne spowolnienia. Wyłączenie persistence przez ustawienie save "" oraz appendonly no w konfiguracji redis.conf eliminuje ten narzut. Dane w cache'u są z natury odtwarzalne – w razie restartu usługi cache po prostu zapełni się ponownie.
Nginx fastcgi_cache vs Redis Full-Page Cache
Zarówno fastcgi_cache, jak i Redis Full-Page Cache, służą do zapisywania całego, wyrenderowanego kodu HTML strony. Gdy zapytanie trafia do serwera, Nginx (lub skrypt z integracją Redisa) odsyła gotowego HTML-a, całkowicie odcinając interpretera PHP od pracy.
Kiedy wybrać poszczególne z nich?
- Nginx fastcgi_cache: Działa bezpośrednio na warstwie serwera www, zapisując wynik w niezwykle wydajnych, współdzielonych obszarach w pamięci (lub na szybkim dysku). Jest to rozwiązanie niemal bezkonkurencyjne pod względem wydajności – zapytanie nigdy nie opuszcza architektury C w Nginx. Stosuje się je idealnie dla stron wizytówkowych, blogów i portali, gdzie zawartość wygląda identycznie dla wszystkich niezalogowanych użytkowników.
- Redis Full-Page Cache: Realizuje to samo zadanie, ale przechowuje HTML w infrastrukturze Redisa. Posiada jedną potężną zaletę: skalowalność horyzontalną. Jeżeli nasz stos LEMP jest rozbity na wiele instancji serwerów Nginx, wszystkie mogą odpytywać jeden scentralizowany klaster Redis. Dla pojedynczego serwera opartego o reverse proxy, to jednak wbudowany w system Nginxa
fastcgi_cachecharakteryzuje się nieznacznie mniejszym narzutem operacyjnym.
Profilowanie wąskich gardeł: Identyfikacja problemów wydajnościowych
Nawet poprawnie skonfigurowany serwer z czasem może zwolnić na skutek złego kodu po stronie aplikacji (np. źle napisanych wtyczek). Profesjonalna administracja stosu wymaga znajomości narzędzi analitycznych, które pozwalają bezbłędnie zlokalizować spowalniający komponent.
Logi wolnych zapytań w MariaDB (Slow Query Log)
Aby odciążyć bazę, pierwszym krokiem jest zidentyfikowanie niezoptymalizowanych zapytań. Po włączeniu w MariaDB logowania, warto uaktywnić rozszerzone statystyki za pomocą zmiennej log_slow_verbosity. Ustawienie wartości na query_plan,explain sprawi, że baza wrzuci do logu nie tylko tekst zapytania, ale też informacje o tym, czy dokonywano pełnego skanu tabeli (zamiast wykorzystania indeksów), co ułatwia optymalizację strukturalną.
Gdy to nie wystarcza, uruchamia się zintegrowany z nowymi silnikami aparat Performance Schema. Przez tabele takie jak events_waits_current, administrator może sprawdzić na żywo, na jakim dokładnie zdarzeniu (ang. wait events) zatrzymały się wątki bazy – czy baza czeka na fizyczny odczyt z dysku I/O, czy doszło do zablokowania rekordu przez blokady mutexów.
Diagnostyka spowolnień w PHP-FPM: slowlog i strace
Kiedy PHP-FPM ulega wysyceniu (w logach błędów widać groźne ostrzeżenia typu "server reached pm.max_children setting"), wina rzadko leży po stronie zbyt małej puli procesów. Prawie zawsze problemem jest zewnętrzna, powolna operacja.
Ustawienie w konfiguracji FPM parametru request_slowlog_timeout (np. na 5s) i przypisanie mu pliku przez slowlog, wymusi na procesie zrzucenie tzw. stack trace (zrzutu ścieżki wywołań w kodzie) za każdym razem, gdy skrypt przekroczy 5 sekund. Często to wystarcza do namierzenia wadliwego kodu.
Jeśli jednak problem nie wynika ze skryptu PHP, ale np. z powolnego rozwiązywania domen DNS przez serwer lub opóźnień zewnętrznego interfejsu API, diagnostyka na poziomie slowloga PHP nie pomoże. W takich sytuacjach inżynierowie sięgają po systemowe narzędzie strace. Dołączenie do zawieszonego procesu php-fpm (za pomocą strace -p) pozwala w czasie rzeczywistym oglądać systemowe odwołania do jądra. Błyskawicznie obnaży to proces bezsensownie oczekujący funkcją poll() lub connect() na opóźniający się zewnętrzny serwer.
Profilowanie procesora: perf i Flamegraph
Gdy mamy do czynienia ze środowiskiem, w którym brakuje mocy na poziomie obciążeń rdzeni (high CPU load), a baza danych nie jest wąskim gardłem, stosuje się narzędzie perf. Polecenie perf record zbierze próbki stosów wywołań ze wszystkich podprocesów php i mariadb. Wygenerowane na tej podstawie wizualne diagramy w postaci Płonących Wykresów (Flamegraphs) pozwolą rzutem oka stwierdzić, która funkcja języka C, wewnątrz jądra Linuxa, rozszerzenia PHP, czy silnika bazy danych, najmocniej obciąża procesor serwera.
Zakończenie
Budowa i optymalizacja architektury opartej na Nginx, PHP-FPM, MariaDB i Redis to proces wykraczający poza instalację usług. Wymaga on ścisłej harmonizacji pomiędzy parametrami serwera www a limitami procesów roboczych i bazodanowych. Prawidłowe zestrojenie parametrów worker_connections, pm.max_children oraz limitów bufora InnoDB w relacji do posiadanej pamięci RAM, jest krytyczne dla osiągnięcia stabilności. Dopełnienie tego stosu przez wbudowane w serwer reverse proxy (fastcgi_cache) oraz obiektowy cache Redisa, wsparte nowoczesnym monitoringiem (strace, Performance Schema), gwarantuje, że środowisko będzie zdolne bez przerw obsłużyć najbardziej wymagający, produkcyjny ruch sieciowy.
W WebOptimo specjalizujemy się w budowie i optymalizacji wydajnych środowisk serwerowych pod WordPress i WooCommerce. Jeśli planujesz wdrożenie lub strojenie stosu LEMP w środowisku produkcyjnym – skontaktuj się z nami. Sprawdź również nasze usługi administracji serwerem, administracji Linux, hostingu WordPress, optymalizacji WordPress oraz administracji MySQL.
FAQ – Stos LEMP
W stosie LAMP Apache obsługuje żądania HTTP i jednocześnie uruchamia interpreter PHP poprzez mod_php, co angażuje ciężkie procesy nawet dla plików statycznych. W stosie LEMP Nginx obsługuje połączenia asynchronicznie, a PHP-FPM działa jako niezależny menedżer procesów, komunikujący się z serwerem WWW przez gniazda unixowe. Dzięki temu LEMP zużywa znacznie mniej pamięci RAM przy dużym ruchu.
Wzór to: pm.max_children = (Całkowity RAM − Rezerwa dla systemu − Nginx − Redis − Bufory MariaDB) / Średni rozmiar procesu PHP. Średni rozmiar procesu sprawdza się na działającym serwerze odczytując RSS (Resident Set Size) procesów php-fpm. Dla WordPressa zazwyczaj wynosi 40-80 MB.
Każdy proces PHP-FPM może nawiązać połączenie z bazą danych. Jeśli pm.max_children wynosi np. 100, a max_connections w MariaDB to domyślne 151, przy nagłym piku ruchu pula połączeń bazy zostanie wyczerpana. Parametr max_connections powinien być o 10-20% większy niż suma pm.max_children ze wszystkich pul PHP.
Nginx fastcgi_cache jest optymalny dla pojedynczego serwera – zapytanie nigdy nie opuszcza architektury C w Nginx, co daje najniższe opóźnienia. Redis Full-Page Cache jest lepszy przy skalowalności horyzontalnej, gdy wiele instancji Nginx odpytuje jeden scentralizowany klaster Redis.
Prawie zawsze problemem nie jest zbyt mała pula procesów, lecz zewnętrzna powolna operacja. Należy ustawić request_slowlog_timeout w konfiguracji FPM, aby zidentyfikować wolne skrypty. Jeśli problem leży poza PHP (np. wolny DNS lub API), narzędzie strace dołączone do zawieszonego procesu php-fpm ujawni, na czym dokładnie czeka.
Nie. Na pojedynczym serwerze LEMP Redis działa lokalnie z limitem maxmemory dostosowanym do budżetu RAM. Kluczowe jest ustawienie polityki maxmemory-policy allkeys-lru, dzięki której Redis automatycznie usuwa najrzadziej używane klucze zamiast zwracać błędy OOM.
Slow Query Log w MariaDB (z rozszerzeniem log_slow_verbosity) identyfikuje wolne zapytania SQL. Performance Schema pokazuje wait events wątków bazy. PHP-FPM slowlog i strace lokalizują wolne skrypty i blokujące operacje systemowe. Narzędzie perf z Flamegraph wizualizuje obciążenie CPU na poziomie funkcji C w jądrze, rozszerzeniach PHP i silniku bazy.