Zend OPcache: pojęcie, instalacja i konfiguracja, wartości php.ini oraz wyłączanie JIT
Zend OPcache to rozszerzenie PHP, które kompiluje skrypty PHP do bytecode i zapisuje go w pamięci współdzielonej, dzięki czemu przy ponownym uruchomieniu tego samego pliku kompilacja jest pomijana. Gdy po włączeniu JIT na serwerze WordPress z PHP 8.3 na wszystkich stronach pojawił się błąd 500, serwer przywrócono do działania, zostawiając OPcache bez zmian i wyłączając tylko JIT.
Od PHP 5.5 OPcache jest domyślnie dołączony do PHP.
1️⃣ Pojęcie Zend OPcache: cache bytecode
Przy każdym żądaniu skrypt PHP przechodzi trzy etapy: odczyt pliku, kompilację do bytecode i wykonanie. Gdy OPcache działa, od drugiego żądania dla tego samego pliku pierwsze dwa etapy znikają i zostaje samo wykonanie.
Pamięć współdzielona, w której OPcache zapisuje bytecode, jest używana wspólnie przez wszystkie workery PHP-FPM. Jeśli do tego samego PHP-FPM podłączonych jest kilka witryn, skrypty tych witryn też trafiają do jednej pamięci współdzielonej.
OPcache zapisuje skompilowany kod PHP, więc przy każdym otwarciu strony nadal odbywa się wykonanie PHP i zapytania do bazy danych. Całkowite pominięcie wykonania PHP przez zapisanie gotowego HTML to zadanie cache stron.
2️⃣ Sprawdzanie instalacji PHP OPcache
To, czy OPcache jest zainstalowany, sprawdzisz w ostatniej linii wyniku polecenia [php -v].
php -vPHP 8.3.22 (cli) (built: Jun 3 2025 17:17:57) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.22, Copyright (c) Zend Technologies
with Zend OPcache v8.3.22, Copyright (c), by Zend TechnologiesJeśli brakuje ostatniej linii, zainstaluj go przez dnf. Pakiet zwykle nazywa się php-opcache; jeśli z repozytorium Remi zainstalowano obok siebie kilka wersji PHP, do nazwy dochodzi numer wersji, jak w php83-php-opcache.
dnf -y install php-opcachePakiet php-opcache z repozytorium Remi ładuje rozszerzenie linią [zend_extension=opcache] w pliku [/etc/php.d/10-opcache.ini]. Po instalacji uruchom PHP-FPM ponownie, aby OPcache obejmował też żądania webowe.
3️⃣ Konfiguracja OPcache: wartości php.ini
Ustawienia OPcache mogą znajdować się w dwóch miejscach: w sekcji [opcache] pliku [/etc/php.ini] oraz w [/etc/php.d/10-opcache.ini].
php --iniConfiguration File (php.ini) Path: /etc
Loaded Configuration File: /etc/php.ini
Scan for additional .ini files in: /etc/php.d
Additional .ini files parsed: /etc/php.d/10-opcache.ini,Pliki z folderu php.d są czytane po php.ini, więc jeśli ta sama pozycja jest wpisana w obu miejscach, obowiązuje wartość z php.d.
Poniższa tabela pokazuje domyślne wartości PHP 8.3 oraz wartości zastosowane na sprawdzanym serwerze WordPress.
| Pozycja | Wartość domyślna w PHP 8.3 | Zastosowana wartość | Znaczenie |
|---|---|---|---|
| opcache.enable | 1 | 1 | Włącza OPcache |
| opcache.enable_cli | 0 | 1 | Używane też w PHP z wiersza poleceń (wp-cli itp.) |
| opcache.memory_consumption | 128 | 1024 | Pamięć współdzielona, w której zapisywany jest bytecode (MB) |
| opcache.interned_strings_buffer | 8 | 16 | Pamięć zapisująca te same ciągi znaków tylko raz (MB) |
| opcache.max_accelerated_files | 10000 | 10000 | Górny limit liczby kluczy, które można zapisać w cache (rzeczywisty limit to liczba pierwsza równa tej wartości lub większa: 16229 dla 10000) |
| opcache.max_wasted_percentage | 5 | 10 | Jeśli brakuje pamięci, a zmarnowane miejsce przekracza ten odsetek, cache jest czyszczony i uruchamiany od nowa |
| opcache.validate_timestamps | 1 | 1 | Sprawdza, czy pliki się zmieniły |
| opcache.revalidate_freq | 2 | 60 | Co ile sprawdzane są zmiany plików (sekundy) |
| opcache.jit | tracing | disable | Tryb JIT (od PHP 8.4 wartością domyślną jest disable) |
| opcache.jit_buffer_size | 0 | 0 | Pamięć JIT; przy 0 JIT nie działa (od PHP 8.4 wartością domyślną jest 64M) |
Wartości wpisane w sekcji [opcache] pliku [/etc/php.ini] podano poniżej. Rozmiar pamięci dobiera się do pamięci serwera, a [opcache.max_accelerated_files] do liczby plików WordPressa.
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=1024
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10
opcache.validate_timestamps=1
opcache.revalidate_freq=60Jeśli w php.ini ponownie wpiszesz linię [zend_extension], rozszerzenie zostanie załadowane dwa razy i pojawi się ostrzeżenie [Cannot load Zend OPcache].
Przy [opcache.revalidate_freq] równym 60 po edycji pliku PHP stary kod może działać jeszcze do 60 sekund.
Na serwerze WordPress, na którym pliki PHP zmieniają się często, zostaw [opcache.validate_timestamps] na 1, aby zmiany plików były sprawdzane. Wartość 0, którą dokumentacja Symfony zaleca dla serwerów produkcyjnych, pasuje do serwerów, na których pliki PHP zmieniają się tylko przy wdrożeniu nowej wersji.
Nawet przy [opcache.validate_timestamps] równym 0 WordPress sam czyści cache zmienionych plików, gdy aktualizujesz z panelu administracyjnego. Jeśli jednak aktualizujesz przez wp-cli albo edytujesz pliki przez SSH, stary kod działa do ponownego uruchomienia PHP-FPM.
4️⃣ Wyłączanie JIT w OPcache
JIT w PHP 8 przyspiesza zadania obciążające procesor, więc w aplikacji takiej jak WordPress, która obsługuje żądania webowe, jego efekt jest niewielki. Również w pomiarze WordPressa opublikowanym w PHP JIT RFC przebieg z włączonym JIT obsłużył 326 żądań na sekundę, a z wyłączonym 315.
Na serwerze WordPress z PHP 8.3.22 włączono JIT ustawieniami [opcache.jit=tracing] i [opcache.jit_buffer_size=128M]. Trzy dni później, w dniu, w którym nawał żądań kilkakrotnie zrestartował workery PHP-FPM, na wszystkich stronach wystąpił błąd 500.
W logu błędów pozostał komunikat [Allowed memory size of 1073741824 bytes exhausted]. Następujące po nim [tried to allocate 4295229440 bytes] to zapis próby jednorazowego przydzielenia 4 GB przy limicie pamięci PHP wynoszącym 1 GB. Po wyłączeniu JIT te same żądania były obsługiwane normalnie.
JIT wyłącza się, wpisując poniższe dwie linie w [/etc/php.d/10-opcache.ini]. Nawet jeśli w [/etc/php.ini] zostały ustawienia JIT, obowiązują wartości z tego pliku.
opcache.jit=disable
opcache.jit_buffer_size=0W PHP 8.3 wartością domyślną [opcache.jit_buffer_size] jest 0, więc bez osobnego ustawienia JIT nie działa. Od PHP 8.4 wartością domyślną [opcache.jit] też jest disable.
5️⃣ Zastosowanie i sprawdzenie ustawień
Zmienione ustawienia zaczynają obowiązywać dopiero po ponownym uruchomieniu PHP-FPM.
systemctl restart php-fpmPo ponownym uruchomieniu pamięć współdzielona OPcache jest opróżniana i przydzielana od nowa z nowymi ustawieniami.
php -i | grep -E '^opcache\.(enable|memory_consumption|revalidate_freq|validate_timestamps|jit) 'opcache.enable => On => On
opcache.jit => disable => disable
opcache.memory_consumption => 1024 => 1024
opcache.revalidate_freq => 60 => 60
opcache.validate_timestamps => On => OnWartości wypisywane przez [php -i] to ustawienia PHP z wiersza poleceń. W rodzinie RHEL PHP-FPM czyta te same pliki [/etc/php.ini] i [/etc/php.d], więc wartości są takie same.
Jeśli wywołasz [opcache_get_status()] w wierszu poleceń, liczba skryptów w cache wyniesie 0. PHP z wiersza poleceń przy każdym uruchomieniu tworzy nową pamięć współdzieloną, więc użycie PHP-FPM sprawdza się, umieszczając poniższy plik w folderze dokumentów webowych i otwierając go w przeglądarce.
<?php
header('Content-Type: text/plain');
$s = opcache_get_status(false);
print_r($s['memory_usage']);
print_r($s['opcache_statistics']);
print_r($s['interned_strings_usage']);
var_dump($s['cache_full']);Jeśli [cache_full] ma wartość true, pamięć współdzielona albo klucze są zapełnione. Po sprawdzeniu od razu usuń ten plik.
Na serwerze, na którym trzy witryny WordPress używają tego samego PHP-FPM, z 1024 MB pamięci współdzielonej zajęte było 317 MB. W cache było od 3 366 do 4 222 skryptów na witrynę, łącznie 11 358.
OPcache zapisuje skrypty pod ich rzeczywistą ścieżką, a dla plików ładowanych ścieżką względną tworzy jeszcze jeden klucz z dołączonym katalogiem roboczym, więc kluczy jest więcej niż skryptów. Przy 11 358 skryptach klucze wypełniły limit 16 229, a bufor ciągów znaków o wielkości 16 MB też nie miał już wolnego miejsca.
Gdy klucze są zapełnione, nowe skrypty nie trafiają do cache i są kompilowane przy każdym żądaniu. W ciągu 5 minut i 21 sekund liczba chybień cache wzrosła z 18 408 do 36 027, ale liczba skryptów w cache pozostała równa 11 358.
Na serwerze z wieloma instalacjami WordPressa albo z dużą liczbą wtyczek ustaw [opcache.max_accelerated_files] z zapasem, aby limit kluczy się nie zapełnił. Przy 20000 rzeczywisty limit kluczy wynosi 32 531. Jeśli bufor ciągów znaków jest pełny, zwiększ też [opcache.interned_strings_buffer].
🔢 FAQ & polecane treści
Cache
Cache: definicja i wszystkie obszary, w których stosuje się buforowanie
Wpis porządkujący dziedziny, w których używa się cache, w tym OPcache, który zapisuje skompilowany kod PHP, oraz cache stron, który zapisuje gotowy HTML.
PHP-FPM
Ostrzeżenie php-fpm max_children: ustal przyczynę w logach, zanim dodasz workery
Wpis o tym, jak na podstawie logów ustalić przyczynę ostrzeżenia, które pojawia się, gdy wszystkie workery PHP-FPM współdzielące pamięć współdzieloną OPcache są zajęte.
PHP-FPM
Czym jest PHP-FPM | Instalacja i konfiguracja PHP-FPM
Wpis o instalacji PHP-FPM, wewnątrz którego działa OPcache, o ustawieniach puli w www.conf i o sposobie ponownego uruchamiania.
ℹ️ Informacja o linkach partnerskich
Treści tej witryny zawierają linki partnerskie. Jeśli odwiedzający kupi produkt lub usługę przez taki link, witryna otrzymuje od sprzedawcy prowizję. Kwota płacona przy tym przez kupującego (podczas promocji spada↓) nie wzrasta. Podane ceny, rabaty i dostępność odnoszą się do chwili pisania i mogą różnić się od stanu faktycznego, dlatego przed zakupem sprawdź je u sprzedawcy. Produkty wybieramy i oceniamy według własnych kryteriów, a prowizja nie wpływa ani na kolejność prezentacji, ani na treść ocen.