PHP OPcache та JIT: повне налаштування
OPcache кешує скомпільований байт-код PHP, усуваючи повторну компіляцію при кожному запиті. JIT (Just-In-Time, доступний з PHP 8.0) компілює байт-код у машинний код — прискорення до 3x для CPU-інтенсивних завдань.
Базове налаштування OPcache
[opcache]
opcache.enable=1
opcache.enable_cli=0
; Пам'ять під кеш байт-коду (мб)
opcache.memory_consumption=256
; Пам'ять під рядки (мб)
opcache.interned_strings_buffer=16
; Максимум файлів у кеші
opcache.max_accelerated_files=20000
; Перевірка змін файлів (0 = ніколи, продакшн)
opcache.validate_timestamps=0
; Перекомпіляція при зміні (dev: 1, prod: 0)
opcache.revalidate_freq=0
; Зберігати коментарі (потрібно для Doctrine/анотацій)
opcache.save_comments=1Налаштування JIT (PHP 8.0+)
; Буфер JIT
opcache.jit_buffer_size=128M
; Режими JIT:
; 0 = вимкнено
; tracing (1255) — найкращий для вебзастосунків
; function (1205) — для CLI/скриптів
opcache.jit=tracingПрофілі для різних оточень
; --- PRODUCTION ---
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.jit=tracing
opcache.jit_buffer_size=128M
; --- DEVELOPMENT ---
opcache.validate_timestamps=1
opcache.revalidate_freq=0 ; перевіряти при кожному запиті
opcache.jit=0 ; JIT заважає xdebugМоніторинг стану OPcache
<?php
$status = opcache_get_status();
$config = opcache_get_configuration();
echo 'Hit rate: ' . round($status['opcache_statistics']['opcache_hit_rate'], 2) . '%';
echo 'Used memory: ' . round($status['memory_usage']['used_memory'] / 1024 / 1024, 1) . ' MB';
echo 'Cached scripts: ' . $status['opcache_statistics']['num_cached_scripts'];Hit rate вище 95% — хороший показник. Нижче 80% — збільште opcache.memory_consumption.
Скидання кешу під час деплою
# Через PHP-CLI
php -r "opcache_reset();"
# Через nginx + PHP-FPM: reload воркерів
php-fpm8.3 -t && systemctl reload php8.3-fpmРеальні помилки JIT і OPcache
Не вдається виділити буфер JIT
PHP Warning: Zend OPcache: Failed to create JIT buffer: mmap() failed [12]: Cannot allocate memory in Unknown on line 0Значення opcache.jit_buffer_size перевищує те, що реально може виділити процес — на VPS із малим обсягом RAM або всередині контейнера з жорстким лімітом cgroup. Іноді причина не в обсязі пам'яті, а в політиках безпеки ядра (SELinux/grsecurity), що забороняють виконувані сторінки пам'яті для JIT — тоді варто дивитися dmesg на предмет відмов.
JIT вимикається при підключенні Xdebug
php -v
PHP 8.2.18 (cli) (built: ...)
with Zend OPcache v8.2.18, Copyright (c), by Zend Technologies
with Xdebug v3.3.1, Copyright (c) 2002-2024, by Derick RethansЯкщо в цьому виводі є Xdebug, JIT фактично не працює, навіть якщо opcache.jit=tracing стоїть у конфігу — розширення несумісні для одночасної роботи. На проді Xdebug узагалі не повинно бути, але це часта причина «JIT нічого не пришвидшує» під час тестування конфігу на staging-сервері з увімкненим налагоджувачем.
Коли JIT не підходить
- Звичайні CRUD-застосунки на WordPress і більшість Laravel-проєктів впираються в I/O (базу даних, диск, мережу), а не в CPU — JIT там дає одиниці відсотків або нічого.
- Спільний shared-хостинг з обмеженням пам'яті на процес — додаткові 64–256 МБ під
jit_buffer_sizeможуть просто не влізти в ліміт. - Код з активним кешем байт-коду, але з увімкненим Xdebug для налагодження — JIT у такій конфігурації марний, вимикайте його на dev-оточеннях явно.
Перевірка результату
| Що перевірити | Команда |
|---|---|
| JIT увімкнений і активний | php -r "var_dump(opcache_get_status()['jit']['enabled']);" |
| Реальний розмір буфера JIT | php -i | grep jit_buffer_size |
| Чи є попередження під час старту FPM | php-fpm8.3 -tt 2>&1 | grep -i jit |
Прапорець -tt у php-fpm виводить розширений тест конфігурації з усіма попередженнями, включно з проблемами завантаження модулів — звичайний -t показує лише фатальні помилки синтаксису.
Перед увімкненням JIT на бойовому сервері протестуйте конкретне навантаження на staging-копії: заміряйте час відповіді ключових сторінок до і після через ab чи wrk. Якщо різниця вкладається в похибку вимірювань — залиште JIT вимкненим, зайвий код у проді без користі збільшує поверхню для рідкісних, важко відтворюваних багів самого JIT-компілятора.
На практиці для типового інтернет-магазину чи блогу різниця між opcache.jit=tracing і повністю вимкненим JIT опиняється в межах статистичної похибки — весь приріст дає вже сам OPcache без JIT.