Урок 03

OPcache: настройка и оптимизация

Что такое OPcache

OPcache — встроенный кеш байт-кода PHP. Файлы .php компилируются в байт-код при первом запросе, сохраняются в памяти. Дальше — не перекомпилируются.

Эффект:

  • Laravel грузится в 3-5 раз быстрее
  • Меньше нагрузки на CPU
  • Больше RPS

Как это работает

Без OPcache:

  1. Запрос → PHP читает 100+ файлов Laravel
  2. Компилирует каждый в байт-код
  3. Выполняет
  4. Забывает
  5. Следующий запрос → всё заново

С OPcache:

  1. Первый запрос → PHP читает и компилирует файлы
  2. Сохраняет байт-код в shared memory
  3. Выполняет
  4. Второй запрос → берёт байт-код из памяти
  5. В 3-5 раз быстрее

Проверка, включён ли

CLI:

php -i | grep opcache.enable
# opcache.enable => On => On

FPM:

php-fpm8.5 -i | grep opcache.enable

Или создай файл info.php:

<?php
phpinfo();

Открой в браузере, ищи OPcache. Если раздел есть — работает.

Где конфиг

  • CLI: /etc/php/8.5/cli/conf.d/10-opcache.ini
  • FPM: /etc/php/8.5/fpm/conf.d/10-opcache.ini

Открой:

sudo nano /etc/php/8.5/fpm/conf.d/10-opcache.ini

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

opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.max_wasted_percentage=10
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
opcache.fast_shutdown=1

Разбор каждой

opcache.enable=1

Включить для FPM.

opcache.enable_cli=0

Отключить для CLI. Composer, artisan, тесты — не кешируют. Иначе кеш CLI забивается мусором.

opcache.memory_consumption=256

256 МБ памяти под кеш. Для Laravel — оптимально. Меньше 128 — мало. Больше 512 — избыточно.

opcache.interned_strings_buffer=16

16 МБ под интернированные строки. Laravel использует много строк — 16 норм.

opcache.max_accelerated_files=20000

Сколько файлов кешируется.

Сколько у Laravel:

find /var/www/skills/api/vendor -name "*.php" | wc -l
# 15000-25000

Ставь 20000-30000. Если меньше — часть файлов не кешируется.

Реальные значения:

  • Laravel + зависимости: 15000-25000 файлов
  • 20000 — норм
  • 30000 — с запасом

opcache.max_wasted_percentage=10

Сколько памяти можно «потерять» перед сбросом. 10% — стандарт.

opcache.validate_timestamps=0

Ключевая настройка для прода.

  • 0 — не проверять изменились ли файлы. Быстрее.
  • 1 — проверять. Медленнее, но при изменении файла кеш обновится.

На проде: 0. Файлы меняются только при деплое, после чего мы сами сбрасываем кеш.

На dev: 1 (или не трогать, по умолчанию).

opcache.revalidate_freq=0

Как часто проверять изменения (в секундах). Работает только если validate_timestamps=1.

opcache.save_comments=1

Сохранять комментарии.

⚠️ Не отключай! Laravel и Symfony используют аннотации в комментариях — роуты, валидация, ORM. Отключишь — всё сломается.

opcache.fast_shutdown=1

Быстрое освобождение памяти. Включи.

JIT (Just-In-Time)

PHP 8.0+ умеет JIT — компиляцию в машинный код во время работы. Ускорение CPU-интенсивных задач.

Настройка:

opcache.jit_buffer_size=128M
opcache.jit=1255

Что значит 1255:

  • 1 — использовать трассировку (tracing JIT)
  • 2 — включить на всех функциях
  • 5 — оптимизация регистров
  • 5 — оптимизация памяти

Для веба JIT помогает мало. Основное время — БД и сеть. Для математики, обработки данных — заметно.

Рекомендация:

  • Веб-приложения: JIT не обязателен
  • API, SaaS: попробуй jit_buffer_size=64M, jit=1255
  • Без JIT: оставь opcache.jit=disable

Сброс OPcache

validate_timestamps=0 = сброс вручную после деплоя.

Способы:

1. Reload PHP-FPM:

sudo systemctl reload php8.5-fpm

2. Artisan:

php artisan opcache:clear

(нужен пакет appstract/laravel-opcache)

3. Через URL:

Создай /var/www/skills/api/public/opcache-reset.php:

<?php
if (($_GET['key'] ?? '') !== 'your-secret-key') {
    http_response_code(403);
    exit;
}
opcache_reset();
echo 'OK';

⚠️ Не оставляй без защиты. Лучше удали после первого использования.

В деплой-скрипт добавь:

curl -s https://example.com/opcache-reset.php?key=your-secret-key
rm /var/www/skills/api/public/opcache-reset.php

Проверка работы

Статус через web:

Установи пакет opcache-gui или opcache-status:

git clone https://github.com/amnuts/opcache-gui /var/www/skills/api/public/opcache

Открой в браузере — увидишь статистику:

  • Cached scripts — сколько файлов
  • Hit rate — % попаданий в кеш
  • Used memory — сколько памяти
  • Wasted memory — потери

Хорошие показатели:

  • Hit rate > 99%
  • Wasted memory < 5%

Если hit rate низкий — мало memory_consumption или max_accelerated_files.

Через CLI:

php -r "print_r(opcache_get_status(false));"

Настройка на CLI

Отдельный конфиг для CLI. Не включай кеш — тесты и artisan должны видеть свежий код.

/etc/php/8.5/cli/conf.d/10-opcache.ini:

opcache.enable_cli=0

Проверка после деплоя

1. Кеш сброшен:

curl -s https://example.com/opcache-status

Смотри Cached scripts — должно быть много.

2. Приложение работает:

curl -I https://example.com
# HTTP/1.1 200 OK

3. Логи чистые:

tail -50 /var/log/php8.5-fpm.log

Частые проблемы

1. Изменения в коде не применяются

Причина: validate_timestamps=0, кеш не сбрасывается.

Решение: sudo systemctl reload php8.5-fpm.

2. Cannot redeclare — ошибка после деплоя

Причина: старый байт-код в кеше.

Решение: сброс OPcache.

3. OPcache не кеширует файлы

Причина: max_accelerated_files меньше числа файлов.

Проверка:

php -r "echo opcache_get_status()['opcache_statistics']['num_cached_scripts'];"

Если близко к max_accelerated_files — увеличь.

4. Медленно работает после деплоя

Причина: кеш пустой, файлы компилируются заново.

Решение: это норма. Первый запрос медленнее, дальше быстро.

Практика: свежая установка

1. Открой конфиг:

sudo nano /etc/php/8.5/fpm/conf.d/10-opcache.ini

2. Поставь:

opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.save_comments=1
opcache.fast_shutdown=1

3. Перезагрузи:

sudo systemctl restart php8.5-fpm

4. Проверь:

curl -I https://example.com

5. Замерь скорость:

ab -n 100 -c 10 https://example.com/

Сравни до и после. Должно быть в 2-5 раз быстрее.

Итог

Минимум для прода:

  • opcache.enable=1
  • opcache.memory_consumption=256
  • opcache.max_accelerated_files=20000
  • opcache.validate_timestamps=0
  • opcache.save_comments=1

После деплоя — sudo systemctl reload php8.5-fpm.

Дальше — PostgreSQL: установка.