Zend OPcache: принцип работы, установка и настройка, значения php.ini и отключение JIT
Zend OPcache — это расширение PHP, которое компилирует PHP-скрипты в байт-код и сохраняет его в разделяемой памяти, чтобы при повторном запуске того же файла компиляция пропускалась. Когда после включения JIT на сервере WordPress с PHP 8.3 на всех страницах появилась ошибка 500, сервер восстановили, оставив OPcache как есть и отключив только JIT.
Начиная с PHP 5.5 OPcache по умолчанию входит в поставку PHP.
1️⃣ Принцип работы Zend OPcache: кеширование байт-кода
При каждом запросе PHP-скрипт проходит три этапа: чтение файла, компиляцию в байт-код и выполнение. Когда OPcache работает, начиная со второго запроса к тому же файлу первые два этапа исчезают и остаётся только выполнение.
Разделяемая память, в которой OPcache хранит байт-код, используется всеми воркерами PHP-FPM совместно. Если к одному и тому же PHP-FPM подключено несколько сайтов, скрипты этих сайтов тоже хранятся в одной разделяемой памяти.
OPcache хранит скомпилированный PHP-код, поэтому выполнение PHP и запросы к базе данных происходят при каждом открытии страницы по-прежнему. Полностью пропускать выполнение PHP, сохраняя готовый HTML, — задача кеша страниц.
2️⃣ Проверка установки PHP OPcache
Установлен ли OPcache, можно проверить по последней строке вывода [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 TechnologiesЕсли последней строки нет, установите его через dnf. Пакет обычно называется php-opcache; если из репозитория Remi сразу установили несколько версий PHP, к названию добавляется версия, например php83-php-opcache.
dnf -y install php-opcacheПакет php-opcache из репозитория Remi загружает расширение строкой [zend_extension=opcache] в файле [/etc/php.d/10-opcache.ini]. После установки перезапустите PHP-FPM, чтобы OPcache применялся и к веб-запросам.
3️⃣ Настройка OPcache: значения php.ini
Настройки OPcache могут находиться в двух местах: в разделе [opcache] файла [/etc/php.ini] и в [/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,Файлы из папки php.d читаются после php.ini, поэтому если одна и та же директива указана в обоих местах, применяется значение из php.d.
В таблице ниже приведены значения PHP 8.3 по умолчанию и значения, применённые на проверенном сервере WordPress.
| Параметр | Значение по умолчанию в PHP 8.3 | Применённое значение | Назначение |
|---|---|---|---|
| opcache.enable | 1 | 1 | Использовать OPcache |
| opcache.enable_cli | 0 | 1 | Используется и в PHP из командной строки (wp-cli и другие) |
| opcache.memory_consumption | 128 | 1024 | Разделяемая память для хранения байт-кода (МБ) |
| opcache.interned_strings_buffer | 8 | 16 | Память, в которой одинаковые строки хранятся один раз (МБ) |
| opcache.max_accelerated_files | 10000 | 10000 | Верхний предел числа ключей, которые можно кешировать (реальный предел — простое число, не меньшее этого значения: 16229 для 10000) |
| opcache.max_wasted_percentage | 5 | 10 | Если память заканчивается, а потерянное место превышает эту долю, кеш очищается и запускается заново |
| opcache.validate_timestamps | 1 | 1 | Проверять, изменились ли файлы |
| opcache.revalidate_freq | 2 | 60 | Как часто проверяются изменения файлов (секунды) |
| opcache.jit | tracing | disable | Режим JIT (с PHP 8.4 значение по умолчанию — disable) |
| opcache.jit_buffer_size | 0 | 0 | Память для JIT; при 0 JIT не работает (с PHP 8.4 значение по умолчанию — 64M) |
Значения, внесённые в раздел [opcache] файла [/etc/php.ini], приведены ниже. Размер памяти подбирается по памяти сервера, а [opcache.max_accelerated_files] — по числу файлов WordPress.
[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=60Если снова добавить в php.ini строку [zend_extension], расширение загрузится дважды и появится предупреждение [Cannot load Zend OPcache].
При [opcache.revalidate_freq], равном 60, после изменения PHP-файла старый код может выполняться ещё до 60 секунд.
На сервере WordPress, где PHP-файлы меняются часто, оставьте [opcache.validate_timestamps] равным 1, чтобы изменения файлов проверялись. Значение 0, которое документация Symfony рекомендует для рабочих серверов, подходит для серверов, где PHP-файлы меняются только при развёртывании новой версии.
Даже при [opcache.validate_timestamps], равном 0, WordPress сам очищает кеш изменённых файлов, когда вы обновляете его из админки. Но если обновлять через wp-cli или править файлы по SSH, старый код продолжит выполняться, пока PHP-FPM не будет перезапущен.
4️⃣ Отключение JIT в OPcache
JIT в PHP 8 ускоряет задачи с большим объёмом вычислений на процессоре, поэтому для приложения вроде WordPress, которое обрабатывает веб-запросы, эффект невелик. В замере на WordPress из PHP JIT RFC тоже прогон с включённым JIT обработал 326 запросов в секунду, а с выключенным — 315.
На сервере WordPress с PHP 8.3.22 JIT включили настройками [opcache.jit=tracing] и [opcache.jit_buffer_size=128M]. Через три дня, в день, когда наплыв запросов несколько раз перезапустил воркеры PHP-FPM, на всех страницах возникла ошибка 500.
В журнале ошибок осталось сообщение [Allowed memory size of 1073741824 bytes exhausted]. Следующая за ним запись [tried to allocate 4295229440 bytes] — это попытка выделить сразу 4 ГБ при лимите памяти PHP в 1 ГБ. После отключения JIT те же запросы стали обрабатываться нормально.
JIT отключается добавлением двух строк ниже в [/etc/php.d/10-opcache.ini]. Даже если настройки JIT остались в [/etc/php.ini], применяются значения из этого файла.
opcache.jit=disable
opcache.jit_buffer_size=0В PHP 8.3 значение [opcache.jit_buffer_size] по умолчанию равно 0, поэтому без отдельной настройки JIT не работает. С PHP 8.4 значение [opcache.jit] по умолчанию тоже disable.
5️⃣ Применение и проверка настроек
Изменённые настройки применяются только после перезапуска PHP-FPM.
systemctl restart php-fpmПосле перезапуска разделяемая память OPcache очищается и выделяется заново с новыми настройками.
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 => OnЗначения, которые выводит [php -i], — это настройки PHP из командной строки. В семействе RHEL PHP-FPM читает те же файлы [/etc/php.ini] и [/etc/php.d], поэтому значения совпадают.
Если вызвать [opcache_get_status()] из командной строки, число закешированных скриптов будет равно 0. PHP из командной строки при каждом запуске создаёт новую разделяемую память, поэтому использование PHP-FPM проверяют, поместив файл ниже в папку веб-документов и открыв его в браузере.
<?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']);Если [cache_full] равно true, разделяемая память или ключи заполнены. После проверки сразу удалите этот файл.
На сервере, где три сайта WordPress используют один PHP-FPM, из 1024 МБ разделяемой памяти было занято 317 МБ. Закешированных скриптов было от 3 366 до 4 222 на сайт, всего 11 358.
OPcache хранит скрипты по реальному пути, а для файлов, загруженных по относительному пути, создаёт ещё один ключ с добавленным рабочим каталогом, поэтому ключей становится больше, чем скриптов. При 11 358 скриптах ключи заполнили предел в 16 229, а в буфере строк размером 16 МБ тоже не осталось свободного места.
Когда ключи заполнены, новые скрипты не кешируются и компилируются при каждом запросе. За 5 минут 21 секунду число промахов кеша выросло с 18 408 до 36 027, а число закешированных скриптов осталось равным 11 358.
На сервере с несколькими WordPress или множеством плагинов задайте [opcache.max_accelerated_files] с запасом, чтобы предел ключей не заполнился. При 20000 реальный предел ключей составит 32 531. Если буфер строк заполнен, увеличьте и [opcache.interned_strings_buffer].
🔢 FAQ & рекомендуемые материалы
Кеш
Кеш: определение и все области, где используется кеширование
Статья, которая разбирает области применения кеша, включая OPcache, хранящий скомпилированный PHP-код, и кеш страниц, хранящий готовый HTML.
PHP-FPM
Предупреждение php-fpm max_children: найдите причину в логах, прежде чем добавлять воркеры
Статья о том, как по журналам определить причину предупреждения, которое появляется, когда заняты все воркеры PHP-FPM, использующие общую разделяемую память OPcache.
PHP-FPM
Что такое PHP-FPM | Установка и настройка PHP-FPM
Статья об установке PHP-FPM, внутри которого работает OPcache, о настройке пула в www.conf и о перезапуске.
ℹ️ О партнёрских ссылках
Материалы этого сайта содержат партнёрские ссылки. Если посетитель покупает товар или услугу по такой ссылке, сайт получает комиссию от продавца. При этом сумма, которую платит покупатель (при акционных скидках сумма снижается ↓), не увеличивается. Указанные цены, скидки и наличие актуальны на момент написания и могут отличаться, поэтому перед покупкой уточняйте их у продавца. Товары выбираются и оцениваются по нашим собственным критериям, а комиссия не влияет ни на порядок, ни на содержание обзоров.