OPcache и JIT

OPcache работает с OxPHP из коробки. Все потоки-воркеры PHP используют общий сегмент памяти OPcache. Скрипты компилируются один раз при первом выполнении, а затем каждый воркер обслуживает их из кеша. Для включения этого совместного использования никакой особой настройки не требуется.

Как OPcache работает с OxPHP

OxPHP регистрируется как именованный SAPI, и OPcache обращается с ним так же, как с другими серверными SAPI. Ключевые особенности:

  • Общий кеш для всех воркеров: все потоки-воркеры PHP используют один и тот же кеш скомпилированных опкодов. Один воркер компилирует файл — выигрывают все воркеры.
  • Никакой компиляции на каждый запрос: после первого запроса к каждому скрипту последующие запросы полностью пропускают этапы парсинга и компиляции.
  • opcache.enable_cli не влияет на OxPHP. Эта настройка применяется только к SAPI с именами cli и phpdbg. OxPHP регистрируется под именем SAPI cli-server, поэтому OPcache управляется исключительно через opcache.enable. Настройка opcache.enable_cli полезна, если вы запускаете PHP CLI в том же контейнере (например, для миграций или команд Artisan). Официальный образ OxPHP поставляется с PHP CLI рядом с бинарником сервера, поэтому вы можете установить opcache.enable_cli=1, если вашим CLI-скриптам полезно кеширование.

Чтобы включить OPcache, минимально необходимо:

ini
[opcache] opcache.enable=1
Note

Официальный Docker-образ OxPHP основан на php:*-zts-alpine, где OPcache статически вкомпилирован в бинарник PHP. НЕ добавляйте zend_extension=opcache в свой INI-файл. Расширение уже загружено, и добавление этой строки вызовет предупреждение при каждом запуске PHP. Нужна только секция конфигурации [opcache].

Рекомендуемые настройки для продакшена

Эти настройки оптимизированы для развёртывания в контейнерах на продакшене, где PHP-файлы не меняются во время работы. Для максимальной пропускной способности отключите проверку временных меток и включите предзагрузку скомпилированных файлов при запуске.

ini
[opcache] opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.validate_timestamps=0 opcache.revalidate_freq=0 opcache.file_update_protection=0 opcache.jit_buffer_size=64M opcache.jit=tracing
Настройка Рекомендуемое значение Описание
memory_consumption 128 Разделяемая память в МБ для скомпилированных скриптов. Увеличьте, если opcache_get_status() показывает мало свободной памяти.
interned_strings_buffer 16 Память в МБ для интернированных строк, разделяемых между всеми воркерами.
max_accelerated_files 10000 Максимальное число кешируемых скриптов. Установите значение выше общего количества ваших .php-файлов.
validate_timestamps 0 При значении 0 OPcache никогда не проверяет файловую систему на изменения. Чтобы применить изменения в коде, перезапустите контейнер или вызовите opcache_reset().
revalidate_freq 0 Интервал в секундах между проверками файловой системы. Не действует при validate_timestamps=0.
file_update_protection 0 Сколько секунд после изменения файла должно пройти, прежде чем файл станет пригоден для кеширования. Установите 0, чтобы кешировать сразу при запуске.

Настройки для разработки

Для разработки включите проверку временных меток, чтобы изменения в коде вступали в силу без перезапуска контейнера. Отключите JIT, чтобы получать более понятные трассировки стека при отладке.

ini
[opcache] opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.validate_timestamps=1 opcache.revalidate_freq=2 opcache.jit_buffer_size=0 opcache.jit=disable

При validate_timestamps=1 OPcache проверяет время изменения файлов каждые revalidate_freq секунд. Это добавляет небольшие накладные расходы на каждый запрос, но позволяет редактировать PHP-файлы и видеть изменения при следующем запросе.

Это рекомендуемая стратегия перезагрузки в режиме разработки для OxPHP. OPcache выполняет проверку встроенно при каждом include, поэтому правки в коде подхватываются при следующем запросе без перезапуска контейнера и без внешнего демона-наблюдателя за файлами. Используйте revalidate_freq=0 для немедленного stat при каждом include (максимальная точность, чуть больше операций ввода-вывода) или revalidate_freq=2, чтобы амортизировать стоимость stat. Показанное выше значение по умолчанию — хороший баланс, особенно если ваш DOCUMENT_ROOT находится на медленном bind-mount (Docker на macOS/Windows).

Что НЕ перезагружается при validate_timestamps

Несколько категорий изменений всё равно требуют перезапуска контейнера (или пересоздания воркера) даже при validate_timestamps=1:

  • Предзагруженные файлы (opcache.preload) подключаются к серверу при запуске и никогда не проверяются повторно. Отредактировали предзагруженный файл — перезапустите контейнер.
  • Состояние инициализации в режиме воркеров — в режиме воркеров автозагрузчик, DI-контейнер и любые объекты, созданные во внешней области видимости, живут в памяти воркера. OPcache перекомпилирует изменённые файлы классов, но воркер не выполнит повторно свою инициализацию. Для циклов воркеров в разработке вызывайте Worker::scheduleExit() в конце каждого запроса (например, под флагом окружения OXPHP_DEV), чтобы пересоздать воркер — это заново выполнит внешнюю область видимости и подхватит все изменения.
  • Кеши на уровне фреймворка — скомпилированный контейнер Symfony, кеш маршрутов/конфигурации/представлений Laravel, оптимизированный classmap Composer. Это .php-файлы, которые OPcache проверяет повторно, но значения внутри них ссылаются на устаревшие пути классов или идентификаторы контейнера. Выполните команду cache:clear вашего фреймворка — одного OPcache недостаточно.
  • Не-PHP-файлы.env, composer.json, конфигурация YAML/JSON, файлы шаблонов, компилируемые вне OPcache. OPcache отслеживает только те файлы, которые он скомпилировал; всё остальное требует перезапуска.

JIT-компиляция

JIT-компилятор OPcache во время выполнения транслирует опкоды PHP в нативный машинный код. Для наилучшей оптимизации используйте режим tracing:

ini
opcache.jit=tracing opcache.jit_buffer_size=64M

JIT даёт наибольший выигрыш для PHP-кода, ограниченного производительностью процессора (CPU-bound): циклы с интенсивными вычислениями, обработка строк, работа с изображениями и рендеринг шаблонов. Для приложений, ограниченных вводом-выводом (I/O-bound), которые большую часть времени ждут ответа от запросов к базе данных или внешних API-вызовов, улучшение минимально.

Чтобы отключить JIT:

ini
opcache.jit=disable opcache.jit_buffer_size=0

Предзагрузка

Предзагрузка OPcache компилирует и кеширует PHP-файлы при запуске сервера, до обработки каких-либо запросов. Это полностью устраняет стоимость компиляции при первом запросе и делает классы и функции доступными глобально без каких-либо накладных расходов на require или автозагрузку.

Настройте предзагрузку в своём INI-файле:

ini
opcache.preload=/var/www/html/preload.php opcache.preload_user=www-data

Создайте скрипт preload.php, который загружает наиболее часто используемые файлы:

preload.php
<?php // preload.php — runs once at server startup require __DIR__ . '/vendor/autoload.php'; // Preload framework core files $files = glob(__DIR__ . '/vendor/symfony/http-kernel/**.php'); foreach ($files as $file) { opcache_compile_file($file); } // Preload hot application paths opcache_compile_file(__DIR__ . '/src/Controller/ApiController.php'); opcache_compile_file(__DIR__ . '/src/Service/UserService.php');
Note

Предзагруженные классы и функции постоянно доступны всем запросам. Их нельзя изменить без перезапуска сервера.

Режим воркеров и предзагрузка

Если вы используете режим воркеров, ваше приложение уже инициализируется один раз: автозагрузчик, конфигурация и соединения с базой данных сохраняются между запросами. Предзагрузка OPcache дополняет это, устраняя накладные расходы на компиляцию опкодов, но не заменяет инициализацию приложения. Эти два механизма работают независимо и могут использоваться совместно.

Применение конфигурации PHP

OxPHP читает конфигурацию PHP из стандартного каталога conf.d. Чтобы предоставить свой собственный INI-файл, используйте Docker-том или инструкцию COPY.

bash
docker run -p 80:80 \ -v ./custom.ini:/usr/local/etc/php/conf.d/custom.ini:ro \ ghcr.io/oxphp/oxphp:0.10.0

Мониторинг состояния кеша

Проверьте текущее состояние OPcache из PHP, чтобы убедиться, что он работает:

php
<?php $status = opcache_get_status(); echo "Cached scripts: " . $status['opcache_statistics']['num_cached_scripts'] . "\n"; echo "Cache hits: " . $status['opcache_statistics']['hits'] . "\n"; echo "Cache misses: " . $status['opcache_statistics']['misses'] . "\n"; echo "Free memory: " . $status['memory_usage']['free_memory'] . " bytes\n";

Если free_memory стабильно мало, увеличьте opcache.memory_consumption.

Смотрите также