OPcache для PHP: настройка и мониторинг
Разбираем, как OPcache ускоряет выполнение PHP-кода за счёт кэширования скомпилированного байт-кода, какие директивы php.ini критичны для production, и как проверять статус кэша и сбрасывать его после деплоя.
Что делает OPcache и почему это критично для производительности
PHP — интерпретируемый язык, и в отсутствие дополнительных механизмов каждый HTTP-запрос к PHP-приложению заставляет интерпретатор заново разбирать (парсить) исходный код всех подключаемых файлов и компилировать его в промежуточный байт-код перед фактическим выполнением — эта работа с точки зрения самого запроса совершенно бесполезна, поскольку исходный код между запросами чаще всего не меняется вовсе.
OPcache — встроенное с версии PHP 5.5 расширение, которое сохраняет уже скомпилированный байт-код файлов в разделяемой памяти между запросами: при первом обращении к файлу PHP компилирует его как обычно и сохраняет результат в кэш, а при всех последующих обращениях — до сброса кэша или изменения файла — сразу берёт готовый байт-код, минуя весь цикл разбора и компиляции заново.
Отсутствие включённого OPcache на production-сервере с PHP — это, пожалуй, самая частая и самая простая в исправлении причина неоправданно медленной работы иначе хорошо написанного PHP-приложения.
Распространённое наблюдение в практике администрирования PHP-серверов
Эта статья разбирает ключевые директивы php.ini, определяющие поведение OPcache, объясняет разницу в разумных настройках для разработки и production, показывает, как проверить текущий статус и эффективность кэша, и разбирает практический вопрос инвалидации кэша после выкладки новой версии кода на сервер.
Проверка, включён ли OPcache, и базовая настройка
Прежде чем настраивать конкретные параметры, стоит убедиться, что расширение OPcache вообще установлено и активно на сервере, — для этого достаточно посмотреть вывод команды с флагом модулей или встроенную функцию PHP.
php -v
php -m | grep -i opcache
php -i | grep opcache.enable
Основная директива opcache.enable=1 включает кэширование для запросов, обрабатываемых через веб-сервер (то есть через PHP-FPM или mod_php), тогда как отдельная директива opcache.enable_cli=1 включает то же самое для запуска PHP-скриптов из командной строки — по умолчанию она чаще всего выключена, поскольку короткоживущие CLI-скрипты редко выигрывают от кэша байт-кода, а фоновые долгоживущие CLI-процессы (например, воркеры очередей) от неё, наоборот, выигрывают заметно.
; /etc/php/8.3/fpm/conf.d/10-opcache.ini
[opcache]
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
Изменения в php.ini или в подключаемых ini-файлах вступают в силу только после перезапуска PHP-FPM (или соответствующего процесса, если используется другой SAPI) — сама структура OPcache живёт в разделяемой памяти процесса и не перечитывает конфигурацию на лету при каждом запросе.
opcache.memory_consumption и opcache.max_accelerated_files
Директива opcache.memory_consumption задаёт объём разделяемой памяти в мегабайтах, выделяемой под хранение скомпилированного байт-кода, — значение по умолчанию (обычно 128 МБ в современных сборках) подходит для небольших проектов, но для крупного приложения с большим количеством файлов может оказаться недостаточным.
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
Отдельная директива opcache.interned_strings_buffer резервирует дополнительную область памяти под интернированные строки — механизм, при котором одинаковые строковые литералы в разных файлах проекта хранятся в памяти лишь однажды, а не дублируются. Для крупных проектов с большим количеством повторяющихся строковых констант увеличение этого буфера с значения по умолчанию (обычно 8 МБ) до 16 или 32 МБ способно дать заметный выигрыш по использованию памяти.
opcache.max_accelerated_files=20000
opcache.max_accelerated_files ограничивает количество файлов, байт-код которых одновременно может находиться в кэше, — значение должно быть заведомо больше реального числа PHP-файлов проекта, включая все зависимости из vendor. Если реальное число файлов превышает установленный лимит, OPcache вынужден вытеснять из кэша часть уже скомпилированных файлов, что резко снижает эффективность кэширования — одни и те же файлы будут периодически перекомпилироваться заново вместо стабильного нахождения в кэше. Узнать реальное число PHP-файлов проекта можно простой командой поиска по каталогу.
find /var/www/site -name "*.php" | wc -l
opcache.validate_timestamps и opcache.revalidate_freq: контроль актуальности
Эти две директивы вместе определяют, как OPcache узнаёт, что файл на диске изменился и его закэшированный байт-код устарел. При opcache.validate_timestamps=1 (обычное значение для разработки) OPcache периодически сверяет время модификации файла на диске с моментом, когда был закэширован его байт-код, и при расхождении перекомпилирует файл заново.
; настройки для окружения разработки
opcache.validate_timestamps=1
opcache.revalidate_freq=0
opcache.revalidate_freq задаёт, как часто (в секундах) выполняется эта проверка временной метки, — значение 0 означает проверку буквально на каждом запросе, что удобно на этапе разработки, когда правки в коде должны отражаться на сайте мгновенно, без ручного вмешательства. Ненулевое значение (например, 60) означает, что после успешной проверки OPcache не будет пересверять время модификации файла ближайшие 60 секунд, даже если файл за это время реально изменится.
; настройки для production
opcache.validate_timestamps=0
На production разумно полностью отключить проверку временных меток директивой opcache.validate_timestamps=0 — это устраняет даже минимальные накладные расходы на сверку файловой системы при каждом запросе, но означает, что OPcache вообще не заметит изменения в файле, пока кэш не будет сброшен явно. Такая конфигурация требует дисциплины в процессе деплоя: любая выкладка новой версии кода обязана сопровождаться сбросом кэша, иначе сервер продолжит выполнять старую, уже закэшированную версию файлов сколь угодно долго.
Инвалидация кэша после деплоя
При opcache.validate_timestamps=0 обновление файлов на диске само по себе никак не влияет на уже закэшированный байт-код — необходим явный шаг сброса кэша как часть самого процесса деплоя, а не отдельная ручная операция, о которой легко забыть под давлением времени.
systemctl restart php8.3-fpm
Перезапуск PHP-FPM — самый надёжный способ сброса, поскольку OPcache хранит данные в разделяемой памяти конкретных процессов, и их полная остановка и повторный запуск неизбежно очищает эту память. Минус подхода — кратковременный провал в производительности сразу после перезапуска, пока кэш заново прогревается на первых запросах, обращающихся к каждому конкретному файлу впервые с чистого состояния.
<?php
if ($_SERVER["REMOTE_ADDR"] === "127.0.0.1" && isset($_GET["token"]) && hash_equals(getenv("OPCACHE_RESET_TOKEN"), $_GET["token"])) {
opcache_reset();
echo "OPcache сброшен";
}
Альтернатива без перезапуска службы — вызов функции opcache_reset() из самого PHP-кода, что позволяет включить сброс кэша прямо в скрипт деплоя как HTTP-запрос к специально защищённому эндпоинту. Такой эндпоинт обязательно нужно защищать — ограничением по IP-адресу, секретным токеном или обоими способами сразу, — поскольку доступный всем сброс кэша по произвольному запросу извне открывает возможность для примитивной атаки на производительность сайта путём постоянного принудительного сброса прогретого кэша.
Мониторинг статуса и эффективности кэша
Встроенная функция opcache_get_status() возвращает подробный массив с текущим состоянием кэша — объём использованной и свободной памяти, число закэшированных файлов, статистику попаданий и промахов, что позволяет оценить, насколько эффективно используются выделенные ресурсы.
<?php
$status = opcache_get_status();
echo "Использовано памяти: " . round($status["memory_usage"]["used_memory"] / 1024 / 1024, 1) . " МБ\n";
echo "Закэшировано файлов: " . $status["opcache_statistics"]["num_cached_scripts"] . "\n";
echo "Hit rate: " . round($status["opcache_statistics"]["opcache_hit_rate"], 2) . "%\n";
Показатель opcache_hit_rate — доля запросов к байт-коду, успешно найденных в кэше, без необходимости повторной компиляции, — на стабильно работающем сервере с прогретым кэшем это значение должно быть близко к 100%. Заметно более низкий hit rate обычно сигнализирует либо о слишком частых сбросах кэша (например, из-за частых деплоев или коротких значений revalidate_freq), либо о переполнении лимита max_accelerated_files с вытеснением файлов из кэша.
Значение wasted_percentage в блоке memory_usage показывает долю памяти, занятой устаревшими фрагментами байт-кода, ожидающими сборки мусора, — при превышении порога, заданного директивой opcache.max_wasted_percentage (по умолчанию 5%), OPcache автоматически инициирует полный перезапуск кэша (restart), что кратковременно снижает производительность, аналогично ручному сбросу.
apt install php8.3-opcache -y
# или для быстрой веб-визуализации статуса подключить open-source
# дашборд наподобие opcache-gui одним PHP-файлом
OPcache и file cache: работа с NFS и общими файловыми системами
На конфигурациях с несколькими серверами приложения, читающими код с общего сетевого хранилища (NFS или аналогичного), стандартное поведение OPcache может работать не так предсказуемо, поскольку разделяемая память кэша локальна для каждого отдельного сервера и не синхронизируется между ними автоматически.
Дополнительный механизм opcache.file_cache задаёт путь на диске для вторичного, файлового уровня кэша байт-кода — он используется как резерв в дополнение к основному кэшу в разделяемой памяти, в первую очередь на случай перезапуска PHP-FPM: вместо полной перекомпиляции всех файлов с нуля после перезапуска, OPcache сначала пробует восстановить байт-код из файлового кэша на диске, что заметно ускоряет прогрев кэша сразу после рестарта службы.
opcache.file_cache=/var/cache/php-opcache
opcache.file_cache_only=0
Для конфигурации с несколькими серверами приложений за балансировщиком нагрузки каждый сервер поддерживает собственный независимый OPcache в своей памяти — это нормально и ожидаемо, поскольку синхронизация байт-кода между серверами не требуется: важно лишь, чтобы процесс деплоя одинаково сбрасывал кэш на всех серверах одновременно, а не только на одном из них, иначе разные серверы будут какое-то время отдавать разные версии приложения.
Разница в настройках для разработки и production
Окружение разработки требует, чтобы любое изменение в PHP-файле немедленно отражалось на сайте при следующем обновлении страницы в браузере, без ручных дополнительных действий вроде перезапуска службы, — это делает opcache.validate_timestamps=1 с opcache.revalidate_freq=0 (или полное отключение OPcache через opcache.enable=0) наиболее удобной конфигурацией для локальной машины разработчика.
На production, напротив, приоритет полностью смещается в сторону максимальной производительности при стабильном, редко меняющемся коде между деплоями — отсюда opcache.validate_timestamps=0 и обязательный явный сброс кэша как часть процесса выкладки новой версии, будь то перезапуск PHP-FPM или вызов opcache_reset() через защищённый эндпоинт.
Постоянная сверка временных меток файлов на каждый запрос — разумная плата за удобство при разработке, но совершенно излишний накладной расход на production-сервере, где код между деплоями физически не меняется.
Общий принцип различия конфигураций OPcache для разных окружений
Промежуточный вариант, встречающийся на staging-окружениях, — оставить opcache.validate_timestamps=1, но с ненулевым opcache.revalidate_freq (например, 2–5 секунд), что даёт компромисс: изменения применяются с небольшой задержкой без необходимости в ручном сбросе кэша, но без накладных расходов на сверку буквально каждого запроса.
Типичные ошибки при работе с OPcache
Полное отсутствие OPcache на production из-за того, что расширение никогда явно не проверялось после установки PHP, — это одна из самых легко исправимых, но при этом самых частых причин неоправданно медленной работы сайта на PHP.
Забытый сброс кэша как часть процесса деплоя при opcache.validate_timestamps=0 — новая версия кода выложена на сервер, но пользователи продолжают видеть поведение старой версии до следующего перезапуска PHP-FPM, что легко принять за баг в самом коде, а не за проблему конфигурации кэша.
Слишком низкий opcache.max_accelerated_files относительно реального размера проекта — постоянное вытеснение файлов из кэша фактически сводит на нет весь смысл кэширования байт-кода, а проблема часто остаётся незамеченной без явной проверки через opcache_get_status().
Незащищённый публичный эндпоинт для вызова opcache_reset() — доступный всем без аутентификации, он превращается в готовый инструмент для примитивной атаки на производительность сайта путём постоянного принудительного сброса прогретого кэша в моменты максимальной нагрузки.
Игнорирование wasted_percentage и связанных с ним автоматических полных перезапусков кэша — частые незапланированные полные сбросы OPcache из-за превышения этого порога снижают среднюю эффективность кэша так же, как и явные ручные сбросы, но остаются незамеченными без регулярного мониторинга статуса.
Итог: простая настройка с заметным эффектом
OPcache — редкий случай в мире оптимизации производительности, где относительно небольшая настройка нескольких директив php.ini даёт заметный и предсказуемый эффект почти для любого PHP-приложения, независимо от конкретного фреймворка или CMS, поскольку устраняет фундаментально бесполезную повторную компиляцию неизменного кода на каждый запрос.
Главное практическое правило — выбирать конфигурацию под конкретное окружение: удобство мгновенного отражения правок на разработке и максимальная производительность со строгой дисциплиной сброса кэша на production. Если не уверены, насколько эффективно OPcache настроен на вашем сервере, или сомневаетесь в правильном значении лимитов под ваш проект, опишите задачу в заявке внизу страницы — поможем проверить и настроить конфигурацию.
После включения и настройки OPcache разумно вернуться к теме через несколько недель реальной эксплуатации и проверить статистику через opcache_get_status() — реальный hit rate и объём использованной памяти на растущем проекте могут заметно отличаться от изначальных ожиданий, и лимиты memory_consumption и max_accelerated_files стоит пересматривать по мере роста числа файлов и сложности приложения.
Почему стоит выбрать нас
Быстрый запуск
Подберём конфигурацию и развернём проект в день обращения.
Надёжность
NVMe-диски, защита от DDoS и резервные копии по расписанию.
Поддержка 24/7
Дежурные инженеры на связи в любое время суток.
Настройка под ключ
Установим CMS, настроим веб-сервер, SSL и почту за вас.
Перенос без простоя
Аккуратно перенесём сайт и базу данных на новый сервер.
Прозрачные цены
Актуальные тарифы и честный подбор без навязывания.
Вопросы и ответы
Включён ли OPcache по умолчанию после установки PHP?
Расширение обычно устанавливается вместе с PHP, но само кэширование включается директивой opcache.enable=1 в php.ini — на многих дистрибутивах и в стандартных сборках это значение уже выставлено в 1 из коробки, но проверять стоит явно, а не полагаться на предположение.
Почему изменения в PHP-коде не применяются после деплоя, хотя код точно обновлён?
Наиболее вероятная причина — OPcache продолжает отдавать закэшированную версию файлов до истечения времени, заданного opcache.revalidate_freq, при включённом opcache.validate_timestamps, либо кэш вообще не проверяет изменения файлов при opcache.validate_timestamps=0, что типично для production-конфигурации.
Как сбросить OPcache после выкладки новой версии кода?
Самый надёжный способ — перезапустить PHP-FPM (systemctl restart php8.3-fpm), поскольку OPcache хранит скомпилированный байт-код в разделяемой памяти конкретного процесса; альтернатива — вызвать функцию opcache_reset() из PHP-скрипта, доступного по HTTP, что не требует прав на перезапуск службы, но требует аккуратной защиты такого эндпоинта.
Сколько памяти выделять под opcache.memory_consumption?
Для среднего проекта обычно достаточно 128–256 МБ; правильный ориентир — реальный суммарный размер PHP-файлов проекта плюс запас на рост, а точный текущий расход памяти можно увидеть через opcache_get_status() в разделе memory_usage.
Что произойдёт, если opcache.max_accelerated_files окажется меньше реального числа файлов проекта?
OPcache начнёт вытеснять из кэша уже скомпилированные файлы, чтобы освободить место под новые, — это резко снижает эффективность кэширования, поскольку одни и те же файлы будут то попадать, то выпадать из кэша, вынуждая PHP периодически перекомпилировать их заново.
Отличаются ли настройки OPcache для разработки и production?
Да, принципиально — на разработке разумно держать opcache.validate_timestamps=1 с низким opcache.revalidate_freq (или вовсе 0) для мгновенного отражения правок в коде, тогда как на production ради максимальной производительности отключают проверку временных меток (validate_timestamps=0) и сбрасывают кэш вручную после каждого деплоя.
Можно ли использовать OPcache вместе с APCu?
Да, это разные механизмы: OPcache кэширует именно скомпилированный байт-код PHP-файлов, тогда как APCu — отдельное хранилище пользовательских данных ключ-значение внутри процесса PHP, и они прекрасно работают одновременно, решая разные задачи, а не конкурируя друг с другом.
Как оплачивать услуги?
Оплата помесячная, для облачных серверов доступна почасовая тарификация. Принимаются карты, банковские переводы и электронные кошельки.
Есть ли круглосуточная поддержка?
Да, дежурные инженеры на связи 24/7.
Выдаёте ли закрывающие документы?
Да, предоставим необходимые документы для оплаты.
Как оставить заявку?
Заполните форму на странице или нажмите «Заказать» — мы свяжемся и поможем с подбором.