OPcache на хостинге: как проверить, включить и сколько это даёт
Самое дешёвое ускорение PHP-сайта. Как понять, работает ли OPcache, какие параметры трогать и почему после деплоя нужен сброс.
Содержание
OPcache хранит скомпилированный код PHP и убирает повторную компиляцию на каждом запросе. На WordPress с двумя десятками плагинов это 30-45 процентов времени генерации страницы. Включается строчкой в настройках PHP и не стоит ничего.
Владелец сайта видит в PageSpeed красные цифры, идёт к подрядчику, и тот предлагает переехать на VPS за 2 500 рублей в месяц. А сайт при этом просто гоняет OPcache в выключенном состоянии, и включение одной строчки в php.ini срезает время генерации страницы вдвое. Бесплатно. Эта статья про то, как проверить, работает ли у вас opcache в PHP, какие параметры реально стоит трогать, сколько ускорения это приносит на обычном сайте услуг и почему после каждой правки кода надо помнить про сброс кэша.

Я веду абонентку шесть лет и почти каждый второй аудит начинаю именно с этой проверки. Она занимает три минуты, а по отдаче обгоняет половину платных плагинов кэширования.
Что вообще делает OPcache
PHP — интерпретируемый язык. При каждом запросе он берёт ваш .php файл, читает его, разбирает на токены, строит дерево, компилирует в байткод и только потом выполняет. Для одной страницы WordPress это происходит не с одним файлом, а с полутора-двумя тысячами: ядро, тема, все активные плагины.
OPcache складывает готовый байткод в разделяемую память. Второй и последующие запросы пропускают чтение с диска и компиляцию: интерпретатор сразу берёт готовое из памяти и выполняет.
Отсюда важное следствие, которое многие упускают. OPcache ускоряет выполнение кода, а не запросы к базе, не внешние API и не отдачу картинок. Если ваш сайт тормозит из-за тяжёлого запроса в MySQL или из-за виджета чата, который тянет 400 КБ скриптов со стороннего домена, OPcache не изменит ничего. Он снимает ровно ту часть времени, которую PHP тратит на превращение текста в исполняемый код.
На типовой странице WordPress с двумя десятками плагинов это в районе 30-45 процентов времени генерации. Отсюда и эффект: TTFB падает почти вдвое, а вы не заплатили ни рубля.
Важно ещё вот что: OPcache идёт в комплекте с PHP начиная с версии 5.5 и в большинстве сборок включён по умолчанию. То есть чаще всего вопрос не «как поставить», а «почему у меня он выключен или настроен на 64 мегабайта».
Как проверить, включён ли OPcache
Три способа, от самого быстрого к самому подробному.
Через панель хостинга
У Timeweb, Beget, REG.RU и большинства российских хостеров в разделе управления PHP есть либо список расширений, либо редактор php.ini. Ищите строку opcache.enable. Если её нет вовсе, смотрите список загруженных модулей: Zend OPcache должен быть там.
У некоторых хостеров рядом есть кнопка сброса кэша. Запомните, где она, ещё пригодится.
Через консоль
Если есть SSH:
php -v
php -i | grep -i opcache
php -r 'var_dump(function_exists("opcache_get_status"));'
Одна ловушка, на которой я сам однажды потерял полчаса. У CLI и у веб-сервера разные конфигурации PHP и разные экземпляры кэша. Параметр opcache.enable_cli по умолчанию выключен, поэтому php -i в консоли может честно показать вам «opcache отключён», хотя на сайте он работает прекрасно. И наоборот: php -r 'opcache_reset();' из консоли не сбросит кэш php-fpm, потому что это другой процесс с другой разделяемой памятью.
Через скрипт в корне сайта
Самый точный способ — спросить у того же SAPI, который обслуживает сайт. Кладём файл в корень, открываем в браузере, смотрим, удаляем.
<?php
// opcache-check.php - положить в корень, посмотреть, СРАЗУ УДАЛИТЬ
header('Content-Type: text/plain; charset=utf-8');
$s = opcache_get_status(false);
if ($s === false) {
exit("OPcache недоступен для этого SAPIn");
}
$d = opcache_get_configuration()['directives'];
printf("Память: занято %.1f МБ, свободно %.1f МБ, мусор %.1f МБn",
$s['memory_usage']['used_memory'] / 1048576,
$s['memory_usage']['free_memory'] / 1048576,
$s['memory_usage']['wasted_memory'] / 1048576);
printf("Файлов в кэше: %d из %dn",
$s['opcache_statistics']['num_cached_keys'],
$s['opcache_statistics']['max_cached_keys']);
printf("Процент попаданий: %.2fn",
$s['opcache_statistics']['opcache_hit_rate']);
printf("Перезапусков: по памяти %d, по хэшу %d, вручную %dn",
$s['opcache_statistics']['oom_restarts'],
$s['opcache_statistics']['hash_restarts'],
$s['opcache_statistics']['manual_restarts']);
printf("validate_timestamps: %s, revalidate_freq: %d секn",
$d['opcache.validate_timestamps'] ? 'да' : 'нет',
$d['opcache.revalidate_freq']);
Файл надо удалить сразу после просмотра. Не потому, что через него что-то взломают, а потому, что забытые диагностические скрипты в корне живут годами и попадают в индекс поиска.
Что читать в выводе:
- Процент попаданий ниже 95 на прогретом сайте означает, что кэш не вмещает весь код и постоянно вытесняет сам себя.
- Свободной памяти около нуля плюс растущий мусор — та же беда, только с другой стороны.
- oom_restarts больше нуля — кэш переполнялся и сбрасывался целиком. Каждый такой сброс это провал скорости на несколько секунд для всех посетителей сразу.
- Файлов в кэше вплотную к лимиту — часть файлов вообще не кэшируется, потому что слоты кончились.
Параметры, которые имеет смысл трогать
Их немного. Всё остальное в дефолтах живёт нормально.
| Параметр | Дефолт | Что ставить сайту услуг | Где меняется |
|---|---|---|---|
opcache.enable | 1 | 1 | php.ini, панель |
opcache.memory_consumption | 128 МБ | 128-256 МБ | только php.ini |
opcache.interned_strings_buffer | 8 МБ | 16 МБ | только php.ini |
opcache.max_accelerated_files | 10000 | 20000 при 20+ плагинах | только php.ini |
opcache.validate_timestamps | 1 | 1 на shared, 0 при деплое скриптом | php.ini, ini_set |
opcache.revalidate_freq | 2 сек | 2-60 сек | php.ini, ini_set |
opcache.save_comments | 1 | 1, не выключать | только php.ini |
Разберу то, что чаще всего настроено неправильно.
memory_consumption. Дефолтные 128 мегабайт закрывают потребности сайта на WordPress с двумя-тремя десятками плагинов. Проблема начинается, когда хостер урезал значение до 64 или даже 32, чтобы влезть побольше клиентов на сервер. Смотрите на свободную память в отчёте: если её меньше 20 процентов, поднимайте.
max_accelerated_files. Это количество слотов под файлы, а не мегабайты. Ядро WordPress само по себе примерно 1 900 файлов. WooCommerce добавляет около 800, крупный конструктор форм 300-500. Двадцать плагинов легко дают 7-9 тысяч файлов, и дефолтные 10 000 оказываются впритык. Значение округляется вверх до ближайшего из внутреннего ряда PHP (3907, 7963, 16229, 32531), поэтому написать 12000 и получить 16229 — нормально.
save_comments. Иногда советуют выключить ради экономии памяти. Не делайте этого: доккомментарии читают аннотации в ряде библиотек, а на WordPress от них зависит разбор заголовков плагинов и тем. Экономия копеечная, а поломка потом ищется долго.
interned_strings_buffer. Буфер под одинаковые строки, которые PHP хранит один раз на все скрипты. Восьми мегабайт дефолта хватает не всегда, шестнадцать берутся почти даром.
Отдельно про то, где это править. memory_consumption, max_accelerated_files, interned_strings_buffer и save_comments имеют уровень PHP_INI_SYSTEM. Их нельзя задать через .htaccess, ini_set() или .user.ini, только в php.ini или через панель хостинга. Если видите в чужой инструкции строку php_value opcache.memory_consumption 256 в htaccess, это либо не работает, либо вообще уронит Apache с ошибкой 500. Про то, какие директивы вообще имеет смысл держать в htaccess, я писал в разборе кэширования через htaccess.
Рабочий блок для php.ini выглядит так:
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.save_comments=1
opcache.max_wasted_percentage=10
После правки php.ini нужен перезапуск php-fpm. На shared-хостинге это делается кнопкой в панели или само в течение минуты-двух.
Сколько это даёт на самом деле
Цифры с одного из моих клиентов: сайт услуг на WordPress, 60 страниц, 24 активных плагина, shared-хостинг за 590 рублей в месяц, PHP 8.2. OPcache у хостера был включён, но с урезанной памятью в 64 МБ и лимитом в 10 000 файлов, кэш переполнялся и сбрасывался по нескольку раз в час.
Замеры делал через curl -w по десять прогонов, брал медиану, кэш страниц на время теста отключал, чтобы мерить именно генерацию.
| Что мерили | Было | Стало | Разница |
|---|---|---|---|
| Время генерации главной | 610 мс | 275 мс | минус 55 процентов |
| TTFB на внутренней странице | 480 мс | 240 мс | минус 50 процентов |
| Список записей в админке | 2 100 мс | 1 150 мс | минус 45 процентов |
| Процент попаданий кэша | 71 | 99,4 | |
| Перезапусков по памяти за сутки | 38 | 0 |
Изменений было ровно два: память подняли до 192 МБ, лимит файлов до 20 000. Ни строчки кода, ни рубля доплаты за хостинг.
Честная оговорка. Это результат на сайте, где OPcache был настроен плохо. Если у вас он работает с дефолтами и не переполняется, включать нечего, а тюнинг даст в лучшем случае процентов пять. Проверить всё равно стоит: три минуты против пятидесяти процентов TTFB — хорошая ставка.
И ещё: если TTFB держится выше 600 мс даже с прогретым OPcache, дело не в компиляции, а где-то ещё. Отдельно про то, как раскопать такой случай, есть разбор долгого ответа сервера на shared-хостинге.
Грабли деплоя: правки не приезжают
Самый дорогой класс ошибок вокруг OPcache связан не с настройкой, а с тем, что кэш держит старую версию файла.
При validate_timestamps=1 PHP проверяет время изменения файла, но не чаще, чем раз в revalidate_freq секунд. С дефолтными двумя секундами вы этого не заметите. А вот если хостер поставил revalidate_freq=300 ради экономии дисковых операций, ваша правка в шаблоне будет приезжать на сайт через пять минут после сохранения. И вы эти пять минут потратите на отладку бага, которого нет.
При validate_timestamps=0 проверок нет вообще. Это плюс несколько процентов скорости и гарантированный сюрприз: файлы на сервере новые, сайт отдаёт старый код, пока кэш не сброшен явно.
Как сбрасывать:
# php-fpm: перезапуск сбрасывает всё
sudo systemctl reload php8.2-fpm
# без root, через веб-запрос к своему же скрипту
curl -s https://example.ru/opcache-flush.php
# WP-CLI, если хостер собрал PHP с opcache.enable_cli=1
wp cli cache clear && php -r 'opcache_reset();'
# cachetool: умеет ходить в сокет php-fpm напрямую
php cachetool.phar opcache:reset --fcgi=/var/run/php-fpm.sock
Повторю ключевое: opcache_reset() из консоли не трогает кэш веб-сервера. Если после деплоя вы дёрнули сброс в SSH и получили старую страницу, кэш никуда не делся, вы просто почистили пустоту.
Для сайтов, которые обновляются скриптом, я держу маленький флеш-эндпоинт с секретом в URL и дёргаю его последним шагом деплоя. Работает надёжнее любых плагинов.
Отдельная разновидность той же беды: правки не приезжают из-за кэша браузера и вечных заголовков на CSS и JS. Симптом похожий, причина другая, и лечится версионированием файлов по времени изменения. Если поймали такое, сначала проверьте, какой из кэшей держит старое, иначе будете чинить не то.
Когда OPcache не поможет
Не надо ждать от него чуда там, где узкое место в другом.
- Медленная база. Тяжёлый запрос на 800 мс останется таким же тяжёлым. Тут лечат индексы и чистка мусорных таблиц.
- Внешние запросы из кода. Плагин ходит за курсом валют к чужому API, тот отвечает за две секунды, вся страница ждёт. Кэш байткода тут не при делах.
- Один конкретный плагин, который жрёт ресурсы. Слайдер, тянущий сорок изображений в каждый запрос, ускорится процентов на пять и останется проблемой. Как искать такого виновника, разобрано в статье про то, какой плагин тормозит сайт.
- Упёршийся в лимиты тариф. Если хостер режет вас по CPU и вы регулярно получаете 508 или 503, OPcache снизит потребление процессора, но потолок по лимитам тарифа останется на месте.
- Фронтенд. Шрифты, картинки без сжатия, блокирующие скрипты. Это вообще не про серверную часть.
И совсем очевидное: если у вас сайт на Тильде или другом конструкторе, PHP на вашей стороне нет, и настраивать нечего.
Про JIT спрашивают отдельно. В PHP 8 он есть, включается через opcache.jit_buffer_size, и на обычном сайте на WordPress даёт в пределах статистической погрешности, потому что нагрузка там на ввод-вывод и базу, а не на арифметику. JIT раскрывается на вычислительных задачах. Для сайта услуг я его не включаю: риск словить нестабильность выше пользы. Preload из PHP 7.4 тоже мимо: он требует перезапуска fpm при каждом изменении кода и на shared-хостинге чаще всего недоступен.
Ещё замечу: смысл всего этого сильно вырастает после перехода на свежий PHP. Если вы до сих пор на 7.4, сначала обновите версию, эффект будет заметнее, чем от любого тюнинга кэша. Порядок и подводные камни описаны в обновлении PHP на хостинге.
Чек-лист на пятнадцать минут
Пройдите по пунктам и закройте вопрос с OPcache раз и навсегда.
- Открыть скрипт проверки в браузере на боевом домене, а не в консоли.
- Записать четыре числа: процент попаданий, свободную память, число файлов против лимита, oom_restarts.
- Если попаданий меньше 95 или oom_restarts больше нуля, поднять
memory_consumptionдо 192 МБ. - Если файлов в кэше больше 80 процентов лимита, поднять
max_accelerated_filesдо 20 000. - Проверить
revalidate_freq. Больше 60 секунд на сайте, который редактируют руками, это вредительство. - Перезапустить php-fpm и через час снять статистику ещё раз.
- Замерить TTFB до и после через
curl -w "%{time_starttransfer}n" -o /dev/null -s https://example.ru/десять раз, взять медиану. - Прописать сброс OPcache в процедуру деплоя и в регламент правок, чтобы потом не искать несуществующие баги.
- Удалить диагностический скрипт из корня.
Пункт девять серьёзно. Я регулярно нахожу на клиентских сайтах чужие info.php и test.php пятилетней давности.
Что делать дальше
Если проверили и всё в порядке, отлично: вы закрыли вопрос за пятнадцать минут и знаете, что скорость упирается во что-то другое. Дальше по списку идут база, плагины и фронтенд.
Если проверить некому или хостер не даёт трогать php.ini, это как раз тот случай, когда нужен человек с доступом и опытом. У меня такая проверка входит в первичный аудит при подключении на обслуживание, вместе с замерами до и после, чтобы разговор шёл о цифрах, а не об ощущениях. Условия и что входит в работы, смотрите в тарифах: годовой 35 000 рублей, помесячный от 15 000. Разработку и дизайн я не делаю, только поддержку и ускорение того, что уже работает.
Если сайт тормозит прямо сейчас и терпеть некогда, напишите через форму на главной, опишите симптом и приложите ссылку. Обычно по первому же ответу сервера видно, стоит ли начинать с OPcache или копать надо в другую сторону.
Частые вопросы
Как проверить, включён ли OPcache
Вывести информацию о PHP на служебной странице и найти раздел OPcache. Если его нет или статус выключен, расширение не работает. Многие панели хостинга показывают это в настройках PHP.
Сколько даёт OPcache
На типовом сайте 30-45 процентов времени генерации страницы. На тяжёлых сборках с большим числом файлов больше. Это самое дешёвое ускорение из существующих.
Почему правки в коде не видны
Потому что кэш держит старую версию файла. На боевом сервере кэш сбрасывают после выкладки, а на время разработки уменьшают интервал проверки изменений.
Когда OPcache не поможет
Когда время уходит не на PHP, а на базу или на внешние запросы. Если страница ждёт тяжёлый запрос к базе, кэш байт-кода не изменит ничего.