Przygotowanie aplikacji PHP na skoki ruchu nie polega na pomnożeniu typowej liczby odwiedzin przez arbitralnie wybrany współczynnik. Wymagane zasoby zależą od liczby jednoczesnych żądań, czasu ich obsługi oraz wykonywanej pracy: strona korzystająca z pamięci podręcznej i operacja odpytująca kilka usług zewnętrznych nie zużywają tych samych zasobów.
Celem operacyjnym jest ustalenie, który komponent ogranicza działanie usługi przy reprezentatywnym obciążeniu, jaki istnieje zapas i co zrobić, gdy zostanie wyczerpany. Testy dostarczają dowodów potrzebnych do podejmowania decyzji; nie gwarantują uniwersalnej zdolności obsługi obciążenia, ponieważ wynik zależy od kodu, infrastruktury, danych i rzeczywistego wzorca korzystania z aplikacji.
Oszacuj obciążenie na podstawie współbieżności i rodzaju operacji

Dzienna lub miesięczna liczba odwiedzin nie wystarcza do oszacowania potrzebnych zasobów. Aplikacja może otrzymywać wiele odwiedzin rozłożonych na wiele godzin i działać z dużym zapasem albo skupiać ruch w ciągu kilku minut i ulec przeciążeniu. Aby oszacować obciążenie, obserwuj natężenie ruchu, czas obsługi żądań oraz udział operacji wykonywanych współbieżnie.
Orientacyjnie, jeśli czas obsługi żądań rośnie, a natężenie ruchu pozostaje niezmienione, więcej żądań jest jednocześnie aktywnych. Dlatego wolna zależność może zwiększać współbieżność nawet wtedy, gdy ruch przychodzący się nie zmienia. Ruch może być też nierównomierny: kampania może spowodować wzrost liczby odsłon stron produktów i wyszukiwań, a zamknięcie okresu — koncentrację logowań, eksportów lub zapisów.
Zacznij od zidentyfikowania tras i operacji wpływających na cele biznesowe. Uwzględnij na przykład publiczne przeglądanie stron, wyszukiwanie, logowanie, składanie zamówień i istotne zadania administracyjne. Rozróżniaj odczyty i zapisy, żądania, których wyniki można buforować, i żądania, których wyników nie można buforować, a także żądania synchroniczne i zadania, które można przetwarzać w kolejce. Nie pozwól, by globalna średnia ukryła wolną lub krytyczną trasę.
Przygotuj reprezentatywny i bezpieczny test
Na podstawie dostępnych danych telemetrycznych, logów dostępu i kalendarza znanych wydarzeń określ jeden lub więcej scenariuszy. Udokumentuj udział żądań przypadający na poszczególne operacje, zmienność natężenia ruchu i czas trwania każdej fazy. Warto przetestować zarówno obciążenie utrzymujące się przez dłuższy czas, jak i jego szybki wzrost, ponieważ ujawniają różne zachowania: stopniowe wyczerpywanie zasobów i gwałtowną reakcję na skok ruchu.
Test należy przeprowadzić w środowisku, które na tyle dobrze odzwierciedla konfigurację produkcyjną, by jego wyniki były użyteczne. Sprawdź różnice w liczbie procesów, limitach połączeń, pamięci podręcznej, wielkości zbiorów danych i zależnościach. Test wykonany na odizolowanej maszynie z małymi tabelami nie dowodzi, jak zareaguje środowisko produkcyjne. Nie generuj obciążenia na ruchu rzeczywistych użytkowników bez wyraźnego planu i upoważnienia.
Uwzględnij ochronę danych już na etapie projektowania scenariusza. Korzystaj z danych syntetycznych lub zanonimizowanych, dedykowanych poświadczeń i minimalnych uprawnień; nie kopiuj danych osobowych do narzędzi obciążeniowych bez odpowiedniej podstawy i zabezpieczeń. Nie dopuść, by testy wysyłały e-maile, pobierały płatności ani powodowały nieodwracalne skutki. W przypadku operacji zewnętrznych używaj środowisk testowych lub kontrolowanych zamienników, pamiętając, że zamiennik nie musi odzwierciedlać opóźnień ani limitów rzeczywistej usługi.
Jednocześnie mierz opóźnienia, błędy i nasycenie zasobów
Rejestruj opóźnienia dla poszczególnych tras i obserwuj percentyle, takie jak p50, p95 i p99. Średnia może pozostawać stabilna, mimo że część żądań staje się bardzo wolna; percentyle lepiej pokazują ten ogon rozkładu. Mierz również odsetek błędów, przekroczenia limitu czasu i liczbę żądań obsłużonych w jednostce czasu. Test generujący wiele żądań, ale także wiele błędów, nie potwierdza użytecznej przepustowości.
Powiąż te pomiary z zasobami i kolejkami. W PHP obserwuj wykorzystanie procesów obsługujących żądania i długość ich kolejki, a także CPU, pamięć i restarty. Jeśli używasz PHP-FPM, sprawdź konfigurację oraz metryki jego procesów i serwera WWW; dostępne nazwy wskaźników zależą od zastosowanej instrumentacji. W bazie danych mierz liczbę aktywnych połączeń, czas oczekiwania na połączenie, wolne zapytania, blokady oraz wykorzystanie CPU lub dysku. Obserwuj również pamięć podręczną, kolejki i zależności zewnętrzne.
Ustal progi powiązane z jakością obsługi i działaniem aplikacji, a nie tylko z wykorzystaniem CPU. Na przykład dla ścieżki zakupowej można określić uzgodnione maksymalne opóźnienie i odsetek błędów, podczas gdy niekrytyczny eksport może poczekać lub być przetwarzany asynchronicznie. Sprawdź, czy zegary i okna obserwacji są porównywalne oraz czy potrafisz powiązać wzrost opóźnień z nasyconym komponentem.
Zlokalizuj pierwsze wąskie gardło, zanim zwiększysz zasoby
Szukaj pierwszego sygnału, który pogarsza się wraz ze stopniowym wzrostem obciążenia. Jeśli rośnie kolejka procesów serwera WWW, a wykorzystanie CPU przez PHP pozostaje wysokie, przyczyną może być kosztowna praca wykonywana przy każdym żądaniu albo zbyt mała liczba dostępnych procesów. Jeśli procesy czekają na połączenia, ale baza danych ma jeszcze zapas, sprawdź limit puli lub konfigurację połączeń. Jeśli baza danych wykazuje wolne zapytania, blokady lub nasycenie, dodanie procesów PHP może zwiększyć obciążenie i pogorszyć problem.
Zależności zewnętrzne również mogą zajmować procesy. Sprawdź czasy nawiązywania połączeń i odpowiedzi, limity częstotliwości żądań oraz zachowanie w przypadku błędów. Zbyt długi limit czasu oczekiwania utrzymuje zajęte zasoby; ponawianie prób bez ograniczeń może zwielokrotnić obciążenie. Ustaw ograniczone czasy oczekiwania i selektywną politykę ponawiania prób, z rosnącymi odstępami, gdy jest to właściwe, oraz nie ponawiaj automatycznie operacji nieidempotentnych bez odpowiednich zabezpieczeń.
Odróżnij niewystarczające możliwości obsługi obciążenia od nieefektywności. Zapytanie skanujące zbyt wiele wierszy, powtarzane wywołania tej samej usługi lub redundantne obliczenia pozostaną kosztowne po dodaniu serwerów. Profiluj reprezentatywne trasy i ograniczaj pracę wykonywaną przy każdym żądaniu: na podstawie dowodów optymalizuj zapytania i indeksy, ograniczaj wyniki, usuwaj zbędne wywołania i korzystaj z buforowania, jeśli pozwalają na to wymagania dotyczące spójności i prywatności. Następnie powtórz test, by sprawdzić, czy poprawa utrzymuje się pod obciążeniem.
Wprowadzaj zmiany w odpowiedniej kolejności i zaplanuj kontrolowaną degradację usługi
Najpierw zmniejsz koszt pracy wykonywanej przy każdym żądaniu i popraw zapytania lub zależności stanowiące ograniczenie. Następnie sprawdź limity współbieżności, procesy serwera WWW i pule połączeń. Zwiększenie liczby procesów może poprawić równoległość, dopóki nie zostaną nasycone CPU, pamięć lub baza danych; skonfigurowanie większej liczby połączeń, niż baza danych jest w stanie obsłużyć, jedynie przenosi kolejkę. Zmieniaj jedną wartość naraz i ponownie wykonuj pomiary.
Skalowanie pionowe — zwiększenie zasobów pojedynczej instancji — może być prostym działaniem, jeśli komponent można rozbudować i nie ma on ograniczeń strukturalnych. Skalowanie poziome — dodanie instancji — wymaga, by wdrożenie, sesje, pliki, zadania i baza danych obsługiwały rozproszoną konfigurację. W razie potrzeby zweryfikuj równoważenie obciążenia, współdzielone lub zewnętrzne przechowywanie danych, stan instancji i wspólne limity, takie jak liczba połączeń z bazą danych. Żadne z tych rozwiązań samo w sobie nie naprawi nieefektywnego zapytania.
Określ, które funkcje należy zachować, gdy brakuje zasobów. Priorytetowo potraktuj uwierzytelnianie, kluczowe operacje lub potwierdzenia transakcji — zależnie od produktu; odłóż raporty, ogranicz kosztowne wyszukiwania lub tymczasowo wyłącz funkcje, bez których można się obejść. Pracę, którą można dokończyć później, kieruj do kolejek i informuj użytkownika o jej stanie. Wyraźnie stosuj limity częstotliwości żądań lub odpowiedzi informujące o przeciążeniu, z rozsądnymi mechanizmami ponawiania. Kontrolowana degradacja usługi powinna zapobiegać utracie potwierdzonych operacji i zapewniać zrozumiałą alternatywę, a nie zwracać fikcyjne potwierdzenie sukcesu.
Aby testy stały się podstawą decyzji operacyjnych, prowadź rejestr zawierający scenariusz, konfigurację, wyniki dla poszczególnych tras, zaobserwowane pierwsze ograniczenie, wprowadzone zmiany i kryterium akceptacji. Powtarzaj test po zmianach w kodzie, infrastrukturze, danych lub istotnych zależnościach. Przed spodziewanym skokiem ruchu sprawdź alerty, dostępne zasoby, procedury wycofania zmian i osoby odpowiedzialne za podejmowanie decyzji.
Lista kontrolna przed skokiem ruchu

- Scenariusz: odzwierciedla prawdopodobne trasy, proporcje, tempo i czas trwania; obejmuje szybki wzrost i długotrwałe obciążenie.
- Bezpieczeństwo: wykorzystuje odpowiednie dane i dedykowane poświadczenia, zapobiega niepożądanym skutkom testu w rzeczywistych systemach i kontroluje miejsce docelowe testu.
- Obserwowalność: koreluje opóźnienia p95/p99 i błędy oraz przepustowość z procesami PHP, bazą danych, pamięcią podręczną i zależnościami.
- Diagnostyka: identyfikuje pierwsze ograniczenie i potwierdza, czy wynika ono z nasycenia zasobów, zapytań, współbieżności czy oczekiwania na usługi zewnętrzne.
- Zmiana: modyfikuje jedną przyczynę naraz, porównuje wyniki i sprawdza, czy nasycenie nie przenosi się do innej warstwy.
- Odporność: określa limity, priorytety, kontrolowaną degradację, komunikację i odzyskiwanie działania bez utraty potwierdzonych operacji.
- Powtórzenie: ustala kryteria akceptacji i ponawia test po istotnych zmianach oraz przed przewidywalnymi wydarzeniami.
Rzetelne określenie potrzebnych zasobów oznacza poznanie reakcji aplikacji na konkretne scenariusze i podejmowanie decyzji z odpowiednim zapasem, a nie pogoń za abstrakcyjną liczbą użytkowników. Pomiary pokazują, gdzie warto inwestować: w optymalizację, dostosowanie współbieżności, dodatkowe zasoby lub politykę kontrolowanej degradacji usługi, która pozwoli zachować użyteczność kluczowych funkcji.



