Kolejkowanie żądań PHP ogranicza liczbę żądań przetwarzanych przez serwer w tym samym czasie, a tym samym określa czas odpowiedzi, liczbę błędów i wrażenia użytkownika. Pokażę ci jak Limity przetwarzania i wyeliminować wąskie gardła oraz osiągnąć spójne dostawy dzięki zharmonizowanym parametrom.
Punkty centralne
Abyś mógł zacząć od razu, podsumuję najważniejsze śruby regulacyjne dla PHP-FPM razem.
- pm.max_childrenOblicz górny limit jednoczesnych procesów PHP, aby dopasować go do pamięci RAM.
- listen.backlogMaksymalizacja krótkoterminowego buforowania prób połączeń podczas szczytowego obciążenia.
- pm.max_requestsRegularnie usuwaj procesy, aby uniknąć wycieków pamięci i rozrostu.
- Limity czasu: konsekwentne ustawianie request_terminate_timeout, max_execution_time i limitów czasu serwera WWW.
- Metrykiosiągnięto maksymalną liczbę dzieci, sprawdzaj kolejkę nasłuchiwania i slowlogi w sposób ciągły.
Skupiam się na jasnych, kluczowych liczbach i wymiernych efektach, tak aby każde dostosowanie do Ograniczenia pozostaje identyfikowalny. W przypadku każdej zmiany monitoruję dzienniki i czasy odpowiedzi przed zaplanowaniem kolejnego kroku i stopniowym zwiększaniem lub zmniejszaniem wartości. W ten sposób zapobiegam efektom ubocznym, takim jak zamiana pamięci, która może Kolejka znacznie dłużej. Dzięki takiemu podejściu kontroluję szczyty obciążenia i utrzymuję stabilne czasy reakcji. Celem jest osiągnięcie zrównoważonego wykorzystania mocy obliczeniowej, które Zasoby wydajnie bez przeciążania hosta.
Jak działa kolejkowanie żądań PHP w PHP-FPM
Każde przychodzące żądanie HTTP wymaga własnego Pracownik, a pracownik obsługuje tylko jedno żądanie na raz. Jeśli wszystkie procesy są zajęte, dalsze połączenia kończą się w module Kolejka i czekać, aż proces stanie się wolny. Jeśli kolejka się rozrasta, czasy odpowiedzi rosną, a błędy takie jak 502/504 pojawiają się częściej. Dlatego zwracam uwagę na rozsądny stosunek liczby procesów do dostępnej pamięci, zamiast ślepo skupiać się na maksymalnej równoległości. W ten sposób osiągam stały współczynnik przepustowości bez RAM lub odłączenie procesora.
Czysty wybór trybów menedżera procesów
Oprócz wartości granicznych tryb pm responsywność i zużycie zasobów:
- pm = dynamicznyDefiniuję start_servers, min_spare_servers i max_spare_servers. Ten tryb jest moim standardem dla zmiennych obciążeń, ponieważ szybko reaguje na wzrosty i utrzymuje ciepłe procesy w gotowości.
- pm = na żądanieProcesy są tworzone tylko wtedy, gdy jest to wymagane i są kończone po przekroczeniu limitu czasu process_idle_timeout. Oszczędza to pamięć RAM w przypadku rzadkich dostępów (administrator, staging, punkty końcowe cron), ale może prowadzić do utraty pamięci RAM w przypadku nagłych szczytów. Rozruchy na zimno i większe opóźnienia. Dlatego używam go wybiórczo i z dużym zapasem.
- pm = statycznyStała liczba procesów. Idealne rozwiązanie, jeśli mam twardy górny limit i szczególnie przewidywalne opóźnienia (np. proxy L7 przed kilkoma, ale krytycznymi punktami końcowymi). Zapotrzebowanie na pamięć RAM jest wyraźnie obliczalne, ale nieużywane procesy zajmują pamięć.
Decyduję, który tryb pasuje do profilu każdej puli. Zwykle używam trybu dynamicznego dla frontendów o zmiennym obciążeniu, trybu na żądanie dla pul narzędziowych i trybu statycznego dla dedykowanych usług o krytycznym opóźnieniu.
Prawidłowe określenie pm.max_children
Najważniejszą dźwignią jest pm.max_children, ponieważ wartość ta określa, ile żądań może być uruchomionych jednocześnie. Obliczam rozmiar początkowy, korzystając z zasady kciuka: (swobodnie dostępna pamięć RAM - 2 GB rezerwy) podzielona przez średnią ilość pamięci na proces PHP. Jako przybliżone założenie, używam 40-80 MB na proces i początkowo zaczynam od 200-300 procesów na hoście 32 GB. Pod obciążeniem na żywo stopniowo zwiększam lub zmniejszam i sprawdzam, czy czas oczekiwania Kolejka spada, a poziom błędu maleje. Więcej informacji na temat wartości początkowych i granicznych można znaleźć na stronie Optymalizacja pm.max_children.
Koordynacja wartości początkowych, zapasowych i zaległości
Ustawiłem pm.start_servers do około 15-30 procent pm.max_children, tak aby wystarczająca liczba procesów była dostępna na starcie i nie było zimnych startów. Za pomocą pm.min_spare_servers i pm.max_spare_servers definiuję rozsądne okno dla wolnych procesów, aby nowe żądania nie czekały, a jednocześnie niepotrzebny czas bezczynności nie wiązał pamięci. Listen.backlog jest szczególnie ważny: Ten bufor jądra krótko przechowuje dodatkowe próby połączeń, gdy wszyscy pracownicy są zajęci. W przypadku szczytów obciążenia ustawiam wysokie wartości (np. 65535), tak aby bufor kolejka nie zatrzymuje się przed pulą FPM. Bardziej szczegółowe informacje na temat interakcji między serwerem WWW, upstream i buforami można znaleźć w przeglądzie Kolejkowanie serwera WWW.
Ograniczenie czasu wykonywania żądań i recykling procesów
Zapobiegam pełzającym skokom pamięci dzięki pm.max_requests, który restartuje każdy proces po X żądaniach. Nienarzucające się aplikacje często działają dobrze z 500-800, jeśli podejrzewa się wycieki pamięci, zmniejszam do 100-200 i obserwuję efekt. Dodatkowo, request_terminate_timeout hermetyzuje wartości odstające, kończąc ekstremalnie długo działające żądania po ustalonym czasie. Spójność jest ważna: utrzymuję max_execution_time PHP i timeout serwera WWW w tym samym korytarzu, aby jedna warstwa nie kończyła się wcześniej niż druga. Ta interakcja utrzymuje Pracownik i chroni basen przed zatorami.
Widoczność kolejek: Dzienniki i metryki
Regularnie czytam dzienniki FPM i zwracam uwagę na maksymalna liczba osiągniętych dzieci, ponieważ ten wpis wskazuje, że osiągnięty został górny limit procesów. Jednocześnie monitoruję kolejkę nasłuchiwania, która ujawnia rosnące zaległości w buforze wejściowym. W połączeniu z request_slowlog_timeout uzyskuję ślady stosu dla powolnych punktów w kodzie i izoluję hamulce bazy danych lub API. Koreluję upstream_response_time z dzienników serwera WWW z request_time i kodami statusu, aby zawęzić źródło długich czasów odpowiedzi. To pozwala mi rozpoznać, czy wąskim gardłem jest PHP-FPM, czy też Baza danych lub sieć upstream.
Profile obciążenia: CPU-bound vs. IO-bound
W przypadku procesów wymagających dużej mocy obliczeniowej procesora skaluję Równoległość Jestem ostrożny i skupiam się ściśle na liczbie vCPU, ponieważ dodatkowe procesy prawie nie przynoszą żadnej przepustowości. Jeśli jest to głównie obciążenie IO z dostępem do bazy danych lub zewnętrznych interfejsów API, mogę zezwolić na więcej procesów, o ile budżet pamięci RAM jest wystarczający. Kasy e-commerce korzystają z dłuższych limitów czasu (np. 300 s) w celu ukończenia metod płatności bez anulowania. Przechwytuję sprzedaż błyskawiczną, ustawiając listen.backlog na wysokim poziomie i zwiększając wolne okno. Informacje na temat równowagi między liczbą procesów a wydajnością hosta są zawarte w przewodniku do PHP-Workers jako wąskie gardło.
Przykładowe obliczenia i wymiarowanie
Najpierw obliczam pamięć przypadającą na proces, a następnie wyprowadzam sensowną wartość Górny limit wyłączony. Następnie testuję pod rzeczywistym obciążeniem i obserwuję, czy kolejka się zmniejsza, a przepustowość wzrasta. Konserwatywne wartości początkowe zmniejszają ryzyko zamiany i utrzymują równy czas odpowiedzi. Następnie udoskonalam je małymi krokami, aby mieć pewność, że nie zauważę żadnych efektów ubocznych. Poniższa tabela zawiera wskazówki dotyczące wartości początkowych i wpływu na Kolejka.
| Parametry | Efekt | Wartość początkowa (przykład) | Wskazówka |
|---|---|---|---|
| pm.max_children | Maks. jednoczesne Procesy | 200-300 (z 32 GB) | Porównanie z budżetem pamięci RAM i rozmiarem procesu |
| pm.start_servers | Początkowa liczba pracowników | 15-30 % od max_children | Unikaj zimnych rozruchów, ale ogranicz do minimum pracę na biegu jałowym. |
| pm.min_spare_servers | Darmowy Pracownik Minimum | z. B. 20 | Bezpośrednie włączanie nowych żądań |
| pm.max_spare_servers | Maksymalny wolny pracownik | z. B. 40 | Ograniczenie zużycia pamięci RAM przez bezczynne procesy |
| listen.backlog | Bufor jądra dla prób połączenia | 65535 | Amortyzacja obciążeń szczytowych i ograniczenie przerw w połączeniach |
| pm.max_requests | Recykling Interwał | 500-800, z wyciekami 100-200 | Minimalizacja nadmiaru pamięci i zawieszeń |
| request_terminate_timeout | Limit twardych żądań | 300-600 s | Zgodność z PHP i limitami czasu serwera WWW |
Praktyczne szablony dla pul PHP FPM
Dla sklepu z wieloma dostępami do odczytu ustawiam umiarkowane wartości Dane dotyczące procesu i zwiększyć wolne okno, aby żądania nie były kolejkowane. W przypadku stron treści z buforowaniem, znacznie mniejsza liczba pracowników jest często wystarczająca, o ile NGINX lub Apache skutecznie dostarczają statyczną zawartość. Oddzielam konfiguracje wielopulowe zgodnie z częściami aplikacji, które mają różne profile pamięci, aby żadna ciężka pula nie wypierała innych. Definiuję oddzielne pule z własnymi regułami limitu czasu dla pracowników cron lub kolejek. W ten sposób utrzymuję interaktywność Ruch uliczny i nie spowalnia żadnych działań użytkownika.
Limity czasu serwera WWW, upstream i gniazda
Rozważam limity czasu FastCGI i proxy od Nginx lub Apache w tym samym oknie, co limit czasu FPM, aby żadna warstwa nie zakończyła się zbyt wcześnie. Wolę gniazda uniksowe niż TCP, jeśli obie usługi działają na tym samym hoście, ponieważ opóźnienie pozostaje minimalne. W przypadku konfiguracji rozproszonych używam TCP ze stabilnymi wartościami keepalive i wystarczająco dużą pulą połączeń. W przypadku wysokiej równoległości, nginx synchronizuje worker_connections i wartości zaległości FPM. Gwarantuje to, że przekierowania pozostają szybkie i unikam czasu bezczynności z powodu zbyt ciasnych połączeń. w górę rzeki-limity.
Buforowanie, OPCache i baza danych jako dźwignie
Rozwiązuję wiele problemów związanych z serwerami, redukując kosztowne operacje i minimalizując Czas reakcji niżej. Włączam OPCache, rozsądnie zwiększam limit pamięci cache i zapewniam wysoki współczynnik trafień. Aby uzyskać powtarzające się wyniki, używam buforowania aplikacji, dzięki czemu procesy PHP są wykonywane szybciej. Po stronie bazy danych optymalizuję powolne zapytania i aktywuję cache zapytań, które są odpowiednie dla używanego systemu. Każda zaoszczędzona milisekunda zmniejsza obciążenie bazy danych. Kolejka i zwiększa przepustowość na pracownika.
Bezpieczne mechanizmy awaryjne i restarty
Aktywuję emergency_restart_threshold i emergency_restart_interval, aby FPM master uruchomił się ponownie, jeśli zbyt wiele dzieci ulegnie awarii w krótkim czasie. Ten kontrolowany restart zapobiega reakcjom łańcuchowym i utrzymuje dostępność usługi. Jednocześnie ustawiłem wyraźne limity pamięci i liczby procesów, aby zapobiec eskalacji. Kontrole stanu po stronie upstream automatycznie usuwają wadliwe backendy z puli i zmniejszają liczbę błędów. Pozwala to utrzymać Dostępność podczas gdy ja badam rzeczywistą przyczynę.
Precyzyjne dostosowanie limitów systemu operacyjnego i systemd
Tak więc listen.backlog faktycznie wchodzi w życie, dostosowuję limity jądra. Wartość OS net.core.somaxconn musi być co najmniej tak wysoka, jak ustawiony backlog, w przeciwnym razie system odetnie kolejkę. Sprawdzam również liczbę dozwolonych deskryptorów plików: W puli FPM mogę ustawić rlimit_files, na poziomie usługi zapewniam LimitNOFILE (systemd), a na poziomie jądra fs.file-max. Serwer WWW potrzebuje podobnych rezerw, aby nie osiągnął swoich limitów wcześniej.
Aby uzyskać bardziej stabilne opóźnienia, zmniejszam vm.swappiness, aby jądro nie wypierało aktywnie używanych stron pamięci przedwcześnie. W konfiguracjach o krytycznym opóźnieniu dezaktywuję Przejrzyste ogromne strony, aby uniknąć długich błędów strony. Jeśli FPM działa przez TCP, synchronizuję również parametry net.ipv4.tcp_max_syn_backlog i reuse/keepalive. Takie szczegóły systemu operacyjnego wydają się niepozorne, ale decydują o tym, czy kolejki gładki lub czy połączenia zostały już odrzucone przed FPM.
Pomiar obciążenia pamięci na proces
Zamiast dokonywać uogólnionych szacunków, mierzę Rzeczywista konsumpcja na pracownika przy rzeczywistym obciążeniu. Używam narzędzi takich jak ps, smem lub pmap, filtruję dzieci php-fpm i uśredniam wartości RSS podczas wykonywania żądań. Ważne jest, aby wziąć pod uwagę współdzielone wykorzystanie OPCache: pamięć współdzielona nie jest liczona wielokrotnie. Wyliczam pm.max_children na podstawie uśrednionej wartości, a także planuję rezerwę, aby maszyna nie wpadła w wąskie gardło nawet podczas szczytów. Swapping przechyla się.
Powtarzam ten pomiar po zmianie funkcji lub wersji. Nowe funkcje, więcej zależności lub zmiany w frameworkach mogą znacznie zwiększyć ślad na proces. Dzięki temu liczba procesów jest realistyczna, a kolejka krótka.
Status PHP FPM, ping i metryki na żywo
Aby szybko ocenić sytuację, aktywuję pm.status_path oraz Punkt końcowy ping (ping.path/ping.response). Powyżej mogę zobaczyć kluczowe liczby, takie jak zaakceptowane połączenia, długość kolejki nasłuchiwania, bezczynne / zajęte procesy, osiągnięte maksymalne dzieci i ich postęp. Odczytuję te wartości okresowo i ustawiam wartości progowe: jeśli kolejka nasłuchiwania stale rośnie, albo zwiększam procesy, albo eliminuję przyczynę powolnych żądań. Jeśli max osiągniętych dzieci skacze w górę, podczas gdy idle pozostaje niski, pula jest zbyt mała lub zablokowana przez biegacze długodystansowi.
Oddzielam również pule o różnych profilach, aby skoki w jednym obszarze (np. import API) nie rzucały interaktywnego ruchu na kolana. W przypadkach diagnostycznych tymczasowo zwiększam log_level i pozwalam slowlogowi przechwycić więcej próbek, ale następnie ponownie go zmniejszam, aby utrzymać niskie obciążenie we/wy.
Przesyłanie, buforowanie i duże treści żądań
Przesyłanie dużych plików może niepotrzebnie wiązać pracowników, jeśli PHP musi najpierw odczytać treść żądania. Upewniam się, że serwer WWW bufory (np. fastcgi_request_buffering dla NGINX), tak aby FPM uruchamiał się tylko wtedy, gdy ciało jest kompletne. Oznacza to, że żaden pracownik nie blokuje się podczas przesyłania. Używam client_max_body_size, post_max_size i max_input_time, aby kontrolować, jak duże i jak długie mogą być żądania bez narażania punktów końcowych. Jeśli pomiędzy nimi znajdują się pliki, alokuję wystarczająco szybką pamięć tymczasową (SSD), aby uniknąć zatorów bufora.
Dla punktów końcowych z bardzo dużymi ciałami (np. eksport/import) definiuję dedykowane pule z własnymi limitami czasu i mniejszą równoległością. Pozostawia to standardowych pracowników wolnych i Kolejka ważnych działań użytkownika.
Połączenia z bazą danych i granice puli
Nawet najlepsze ustawienie FPM jest bezużyteczne, jeśli Baza danych wcześniej ograniczone. Dopasowuję maksymalną liczbę jednoczesnych procesów PHP do rzeczywistej dostępnej pojemności bazy danych. W przypadku trwałych połączeń lub pul połączeń upewniam się, że suma wszystkich pul wynosi na stronie max_connections pozostaje. Jeśli istnieje wiele krótkich zapytań, pomaga to ograniczyć równoległość PHP w umiarkowanym stopniu, aby baza danych nie ulegała awarii między tysiącami sesji.
Wolne transakcje szybko powodują zaległości w kolejce FPM. Dlatego analizuję czasy oczekiwania na blokadę, wykorzystanie indeksów i plany zapytań. Każda redukcja czasu wykonywania DB natychmiast zmniejsza PHPCzas trwania dokumentu i zmniejsza długość kolejek.
Wydania i wdrożenia bez skoków
Podczas wdrażania nowych wersji unikam zimnych pamięci podręcznych i burz procesów. Używam przeładowanie zamiast twardych restartów, aby istniejące żądania worker kończyły się czysto (uwaga na process_control_timeout). Rozgrzewam OPCache na wczesnym etapie, uruchamiając ścieżki krytyczne raz przed przełączeniem lub pracując z ładowaniem wstępnym. Zapobiega to jednoczesnemu parsowaniu plików klas przez wielu pracowników, a proces Czas reakcji wzrasta skokowo.
W przypadku strategii niebieskiej/zielonej lub kanarkowej stopniowo zwiększam obciążenie i monitoruję strony stanu. Dopiero gdy kolejka, wskaźnik błędów i opóźnienia pozostają stabilne, zwiększam udział ruchu. To kontrolowane podejście chroni przed szczytami obciążenia podczas wdrażania.
Specjalizacje dotyczące kontenerów i maszyn wirtualnych
W kontenerach, postrzegane Całkowita pojemność pamięci często niższe niż raporty hosta. Dopasowuję pm.max_children ściśle do limitu cgroup i planuję rezerwę przeciwko zabójcy OOM. Limity pamięci w PHP (memory_limit) i footprint na proces muszą się zgadzać, w przeciwnym razie pojedyncza wartość odstająca wystarczy do zamknięcia kontenera.
Jeśli w kontenerze nie ma wymiany, twarde anulowanie jest bardziej prawdopodobne. Właśnie dlatego utrzymuję konserwatywne procesy, aktywuję recykling i monitoruję szczyty RSS w obciążeniu produkcyjnym. Kilka szczupłych pul jest tutaj często bardziej niezawodnych niż jedna duża, monolityczna pula.
Kontrolowana degradacja i przeciwciśnienie
Jeśli Kolejka Polegam na kontrolowanej degradacji: celowo dostarczam 503 z ponowną próbą dla niekrytycznych punktów końcowych w przypadku przeciążenia, ograniczam drogie funkcje (np. wyszukiwanie na żywo) i ograniczam równoległy dostęp do hotspotów. Dzięki temu system jest responsywny, podczas gdy ja usuwam przyczynę, zamiast narażać wszystkich użytkowników na przekroczenie limitu czasu.
Krótkie podsumowanie
Przynoszę Kolejkowanie żądań PHP pod kontrolą dzięki sprytnemu dopasowaniu liczby współbieżnych procesów do budżetu pamięci RAM i rodzaju obciążenia. Wysokie wartości backlogu buforują szczyty, timeouty na wszystkich poziomach zgrabnie współgrają, a recykling usuwa pełzające problemy z pamięcią. Dzienniki i metryki pokazują mi, czy kolejka rośnie, gdzie utknęły żądania i kiedy powinienem ją zacieśnić. Dzięki starannym dostosowaniom i ukierunkowanemu buforowaniu skracam czas przetwarzania na żądanie i zwiększam przepustowość. W ten sposób serwery dostarczają spójne dane i unikają kosztownych awarii. Limity czasu w życiu codziennym.


