Aplikacja może mieć idealne zapytania i cache, a mimo to odpowiadać wolno — bo wąskim gardłem jest samo PHP. Domyślna konfiguracja PHP-FPM na serwerze z panelem hostingu nie jest projektowana pod Laravel: za mało procesów, za mały OPcache, brak preloadu. Ten poradnik to produkcyjna konfiguracja PHP pod Laravel — z liczbami, kalkulacją procesów FPM i komendami, które składają się w skrypt wdrożeniowy.
Najważniejsze: Najważniejsze — OPcache z
memory_consumption128–256 MB imax_accelerated_files20 000 eliminuje kompilację plików przy każdym żądaniu.opcache.validate_timestamps=0daje kolejne kilka procent (wymaga czyszczenia przy deployu). PHP-FPM skaluj od pamięci RAM:max_children = RAM / 60–80 MB. Całość domykacomposer install --optimize-autoloaderiphp artisan optimizew każdym wdrożeniu.
Co robi OPcache i dlaczego to podstawa
PHP to język kompilowany do kodu pośredniego (opcodes) przy każdym uruchomieniu skryptu. Bez OPcache każde żądanie HTTP oznacza: odczyt kilkuset plików z dysku, parsowanie, kompilację — a dopiero potem wykonanie. OPcache zapamiętuje skompilowane opcodes w pamięci współdzielonej między procesami FPM, więc kolejne żądania pomijają cały ten etap.
Dla aplikacji Laravel skala problemu jest duża: framework + vendor + kod aplikacji to typowo 5 000–20 000 plików PHP. Bez OPcache każde żądanie płaci za ich kompilację; z OPcache — raz, przy pierwszym żądaniu po starcie.
Produkcyjna konfiguracja OPcache
; /etc/php/8.3/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
opcache.fast_shutdown=1
| Ustawienie | Wartość | Dlaczego |
|---|---|---|
memory_consumption |
128–256 MB | Poniżej 128 MB cache się przepełnia i „mieli" pliki (thrashing) |
max_accelerated_files |
20 000 | Musi pomieścić vendor + aplikację; realna wartość to najbliższa liczba pierwsza ≥ podanej |
interned_strings_buffer |
16 MB | Mniej duplikatów stringów w pamięci |
validate_timestamps |
0 na produkcji | OPcache nie sprawdza dat plików przy każdym żądaniu — oszczędność I/O |
save_comments |
1 | Potrzebne dla adnotacji (doctrine/annotations, atrybuty w refleksji) |
Uwaga:
validate_timestamps=0oznacza, że zmiany plików nie są widoczne do czasu czyszczenia OPcache. Twój deploy musi kończyć sięopcache_reset()(np. przez skrypt PHP wywołany z CLI na sockecie FPM) albo restartemphp8.3-fpm. Włączanie tego na serwerze, gdzie pliki zmienia się ręcznie — proszenie się o awarię.
Jak sprawdzić stan cache po wdrożeniu
php -i | grep opcache
# albo w aplikacji:
php -r 'print_r(opcache_get_status(false));'
Interesują Cię opcache_hit_rate (cel: >99%) i used_memory vs memory_consumption (jeśli blisko limitu — zwiększ).
opcache.preload — kompilacja na starcie procesu
Preload (PHP 7.4+) kompiluje wskazane pliki przy starcie FPM i trzyma je na stałe — zamiast leniwie przy pierwszym żądaniu. W Laravelu preloaduje się framework i najczęściej używane klasy:
opcache.preload=/var/www/app/preload.php
opcache.preload_user=www-data
<?php
// preload.php — świadomie wąska lista (nie preloaduj całego vendor)
require __DIR__.'/vendor/autoload.php';
$files = [
__DIR__.'/vendor/laravel/framework/src/Illuminate/Foundation/Application.php',
// ... klasy z największym „wkładem" w czas bootstrapu
];
foreach ($files as $file) {
opcache_compile_file($file);
}
Realny zysk z preloadu w Laravelu to kilka procent (framework i tak wchodzi do OPcache przy pierwszych żądaniach) — ale na serwerach z częstymi restartami FPM (deploye, autoscaling) różnica jest odczuwalna, bo pierwsze żądania po restarcie są natychmiast szybkie.
Wskazówka: Zanim zbudujesz preload, zmierz co warto preloadować. Wąskie gardło to zwykle bootstrap Laravela —
Illuminate\Foundation, kontener, router. Pakietbrick/opcache-preload-generatorpotrafi wygenerować listę plików z realnego ruchu zamiast zgadywania.
JIT — czy warto włączać w Laravelu?
JIT (PHP 8.0+) kompiluje gorące ścieżki opcodes do kodu maszynowego. Brzmi jak game changer, ale w praktyce aplikacje Laravel spędzają czas w I/O (baza, Redis, HTTP), a nie w obliczeniach CPU. Zmierzony zysk w typowych CRUD-ach: 0–10%, przy wyższym zużyciu pamięci.
opcache.jit=tracing
opcache.jit_buffer_size=64M
Włączaj tylko po pomiarze (k6 przed/po) i tylko jeśli masz wolny budżet pamięci. Dla aplikacji robiących realną matematykę w PHP (przetwarzanie obrazów, obliczenia, parsowanie dużych plików) JIT potrafi dać kilkanaście procent — dla reszty to placebo z kosztem RAM.
PHP-FPM — kalkulacja procesów i tryby pracy
Najważniejszy parametr to pm.max_children — maksymalna liczba procesów obsługujących żądania. Zbyt mało: żądania czekają w kolejce (użytkownik widzi „wiszącą" stronę). Zbyt dużo: procesy konkurują o RAM, system wchodzi w swap, OOM killer zabija FPM.
Kalkulacja od pamięci:
max_children = (RAM dostępne dla PHP) / (średni rozmiar procesu)
Średni proces Laravel to typowo 40–80 MB (z OPcache i bibliotekami). Na serwerze 4 GB, gdzie PHP dostaje 2,5 GB: 2500 / 60 ≈ 40 procesów. Zmierz realny rozmiar: ps -o rss= -C php-fpm8.3 | awk '{s+=$1} END {print s/NR/1024 " MB"}'.
; /etc/php/8.3/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.max_requests = 500
pm.process_idle_timeout = 10s
| Tryb | Charakterystyka | Kiedy |
|---|---|---|
dynamic |
Pula rośnie/maleje z ruchem | Domyślny wybór — ruch zmienny |
static |
Stała liczba procesów | Stały wysoki ruch — eliminuje narzut skalowania |
ondemand |
Procesy tworzone na żądanie | Bardzo mały ruch — oszczędza RAM, wolniej reaguje |
pm.max_requests = 500 to bezpiecznik na wycieki pamięci: proces obsłuży 500 żądań i zostanie zastąpiony świeżym. Dla aplikacji z ciężkimi bibliotekami (PDF, obrazy) ustaw 100–200.
Uwaga:
pm.max_childrenliczony „na oko" to klasyczna przyczyna awarii pod skokiem ruchu. Zrób test:ab -n 1000 -c 50 https://staging.example.com/i obserwujpm.max_children reachedw logu FPM (grep max_children /var/log/php8.3-fpm.log). Jeśli limit jest osiągany przy normalnym ruchu — podnieś go albo dodaj RAM; nie obniżaj jakości usługi.
Deploy — komendy, które domykają temat
Pełny blok wdrożeniowy (kolejność ma znaczenie)
composer install --no-dev --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan queue:restart # jeśli używasz kolejek
# reset OPcache (validate_timestamps=0) — np. przez cgi-fcgi albo restart FPM:
sudo systemctl reload php8.3-fpm
--optimize-autoloader generuje mapę klas zamiast przeszukiwania systemu plików — na produkcji zawsze. Komendy artisan opisuję szerzej w optymalizacji wydajności aplikacji Laravel, a automatyzację całego procesu w CI/CD i DevOps dla Laravel.
Hosting — kiedy współdzielony przestaje wystarczać
Na hostingu współdzielonym nie kontrolujesz OPcache, FPM ani wersji PHP — dostajesz to, co dał operator. Sygnały, że czas na VPS: aplikacja ma stały ruch powyżej kilkudziesięciu tysięcy odsłon miesięcznie, potrzebujesz Redis, kolejek i workerów, albo limity max_children u operatora powodują kolejkowanie żądań w godzinach szczytu. VPS (albo dedyk) daje pełną kontrolę nad php.ini, FPM i OPcache — czyli nad wszystkim, co opisuje ten artykuł. Warstwę serwera HTTP omawiam w Nginx czy Apache dla Laravel.
Najczęściej zadawane pytania
Jakie ustawienia OPcache są najlepsze dla Laravel?
opcache.memory_consumption=192, opcache.max_accelerated_files=20000, opcache.interned_strings_buffer=16, a na produkcji opcache.validate_timestamps=0 z czyszczeniem cache przy każdym deployu. Po wdrożeniu sprawdź opcache_get_status(): hit rate powinien być powyżej 99%, a zużycie pamięci poniżej limitu.
Jak obliczyć pm.max_children dla PHP-FPM?
Podziel RAM przeznaczony dla PHP przez średni rozmiar procesu (40–80 MB dla Laravel z OPcache). Serwer 4 GB z 2,5 GB dla PHP: ok. 40 procesów. Zweryfikuj pomiarem (ps -o rss=) i testem obciążeniowym — jeśli log FPM pokazuje max_children reached, limit jest za niski.
Czy validate_timestamps=0 jest bezpieczne?
Tak, jeśli deploy kończy się czyszczeniem OPcache (restart FPM albo opcache_reset()). Nie jest bezpieczne, gdy pliki zmienia się poza procesem wdrożeniowym — wtedy zmiany nie będą widoczne do restartu. To standard na produkcji, nigdy w development.
Czy JIT przyspieszy aplikację Laravel?
Zwykle minimalnie — Laravel spędza czas w I/O, nie w CPU. Zmierzony zysk w typowych aplikacjach to 0–10% przy wyższym zużyciu pamięci. Włączaj po teście porównawczym, nie „na wiarę". Realne przyspieszenie dają OPcache, preload i dobrze dobrane FPM.
Co daje opcache.preload w Laravelu?
Kompiluje wskazane pliki (framework, kluczowe klasy) przy starcie procesów FPM — pierwsze żądania po restarcie są szybsze, a bootstrap nie kompiluje klas leniwie. Zysk jest największy na serwerach z częstymi restartami FPM (deploye, autoscaling). Listę plików generuj z realnego ruchu, nie z całego vendora.
Czy hosting współdzielony wystarczy dla aplikacji Laravel?
Dla prostych stron i małego ruchu — tak. Gdy pojawiają się kolejki, Redis, stały ruch i wymagania na czasy odpowiedzi, limity operatora (procesy FPM, brak kontroli nad OPcache) stają się wąskim gardłem. Wtedy VPS z własną konfiguracją PHP to naturalny następny krok.
👉 Aplikacja działa wolno mimo dobrego kodu? Sprawdźmy warstwę PHP i serwera — opisz projekt przez formularz. Zobacz też utrzymanie techniczne i SLA.
📖 Zobacz również: optymalizacja wydajności aplikacji Laravel, Nginx czy Apache dla Laravel, CI/CD i DevOps dla Laravel oraz Laravel Octane.