• База знань
  • /
  • Блог
  • /
  • Wiki
  • /
  • ONLINE CHAT
+380 (44) 364 05 71

Стаття також доступна російською (перейти до перегляду).

Дізнайтесь, як OPcache, Redis, APCu і PHP-FPM допомагають прискорити сайт без зміни обладнання

Зміст:

У попередніх статтях ми вже розглянули питання швидкості роботи додатків на ВПС в залежності від обладнання та типу віртуалізації. Також з’ясували, що таке трейсінг та як його використання дозволяє знайти вузькі місця у програмі. Тепер сконцентруємося на питанні прискорення роботи додатку за рахунок оптимізації роботи самого PHP, зокрема, вдосконалення механізмів кешування коду та даних, а також обрання оптимального режиму роботи препроцесору для кожного типу веб-додатку.

Навіщо потрібна оптимізація роботи PHP на VPS

Оптимізація PHP є одним із шляхів збільшення продуктивності роботи додатку при незмінних характеристиках обладнання. Ця теза вже не раз була перевірена на практиці із виходом чергового релізу PHP – продуктивність з кожною новою версією впевнено зростає.

Параметр TTFB (Time to First Byte) є одним із базових показників продуктивності роботи будь-якого додатку або веб-сторінки. Він визначає час відповіді VPS-серверу на запит клієнта – чим він менший, тим краще.        

Виділимо основні шляхи покращення цієї характеристики:

  • Розширення або вдосконалення роботи серверного обладнання;

  • Застосування систем CMS та CDN управління контентом та його доставки по мережі;

  • Зменшення розміру даних;

  • Кешування;

  • Оптимізація роботи PHP.

Як показує простий розрахунок, збільшувати продуктивність за рахунок серверного обладнання доцільно лише при порівняно невеликих навантаженнях. Це дозволить уникнути значних фінансових витрат. При значних навантаженнях, наприклад, у випадку «розкрученого» Інтернет-магазину із постійним ростом кількості запитів до серверу, найбільш ефективним шляхом може стати оптимізація роботи самого PHP. Результат оптимізації може досягти тих самим значень показників, як і у випадку оновлення обладнання – зменшення навантаження на CPU, покращення значення параметру TTFB тощо. 

Шлях PHP-оптимізації полягає у збалансованому керуванні процесами та вдосконаленні роботи компілятора за рахунок використання різних підходів до кешування коду та даних в залежності від типу додатку.

Всі наведені нами стратегії кешування даних розглянуті на прикладі оптимізації роботи відомого PHP-додатку з відкритим вихідним кодом під назвою ownClowd, котрий орієнтований на забезпечення сумісної роботи з файлами та синхронізацію даних.  

OPcache – кеш байткоду

Компілятор препроцесору PHP під час своєї роботи перетворює вихідний код додатку у проміжний низькорівневий байткод, котрий одразу ж виконується і після цього знищується. І так при кожному запиті. По суті, відбувається повторення компілятором однієї й тієї ж дії зі створенням постійного навантаження на серверні ресурси. Особливо це відчувається при виконанні однакових запитів із компіляцією однієї й тієї ж ділянки вихідного коду сценарію. Така ситуація може бути виправданою лише в тому разі, якщо на production-серверах вихідний код додатку буде щосекунди змінюватися, чого, як правило, не буває в реальності. І тому природний шлях оптимізації цього процесу це кешування байткоду у RAM-пам’яті. У такому разі із ланцюга процесу обробки коду викидається одна ланка – етап компіляції у байткод.

Звісно, увесь код додатку закешувати неможливо, але окремі, найбільш навантажені ділянки кешувати можна. Це у рази зменшує навантаження на CPU та дає змогу підвищити продуктивність роботи додатку та зменшити значення параметру TTFB. Для цієї мети були розроблені спеціальні інструменти. 

OPCache це розширення, котре забезпечує виконання двох функцій – кешування створеного компілятором байткоду у RAM-пам’яті та його оптимізацію. І одне й інше сприяє підвищенню швидкості обробки коду. Починаючи з версії PHP 5.5.0 розширення входить до складу ядра препроцесору та увімкнено за замовчуванням, що спрощує його використання. Розширення офіційно рекомендоване до використання у якості засобу кешування та забезпечене технічною підтримкою.         

Слід зазначити, що OPCache прийшов на зміну відомому інструменту кешування – розширенню APC (Alternative PHP Cache), остання версія 3.1.13 котрого працює лише із PHP 5.4. Нині його розробка припинена. На відміну від APC, OPCache більш ефективно використовує загальну пам’ять PHP, минуючи процес технічного управління нею – фрагментацію, вивільнення та повернення даних тощо. Це дає змогу економити ресурси та підвищити ефективність роботи кешера.

Починаючи з версії PHP 8.0, з’явилася надбудова над OPCache – JIT-компілятор. Він компілює вихідний код програми не у байткод, а відразу у машинний код та розміщує його у RAM-пам’яті. Це забезпечує ще більший рівень оптимізації роботи препроцесора. Керувати роботою JIT-компілятора можна за допомогою опцій, розміщених у файлі php.ini, про що поговоримо пізніше.  

Встановлення та налаштування

Для версій препроцесору ≥ 5.5.0 розширення OPCache вже присутнє у ядрі та увімкнене, і тому його встановлювати не потрібно. Відповідно, опція opcache.enable у файлі php.ini буде також увімкнена. Щоб перевірити це можна скористатися наступною командою:

# php -r 'phpinfo();' | grep opcache.enable

Для версій із діапазону 5.2 ≤ 5.4 розширення можна встановити за допомогою наступної команди:

# pecl install zendopcache-beta

Для оптимальної роботи розширення рекомендовані наступні значення параметрів, котрі вказуються у файлі php.ini:

opcache.memory_consumption=128
opcache.max_accelerated_files=8000
opcache.revalidate_freq=60
opcache.validate_timestamps=1
opcache.interned_strings_buffer=8
opcache.enable=1
opcache.fast_shutdown=1
opcache.jit=tracing/on

Дамо короткі пояснення стосовно вказаних директив.

opcache.memory_consumption – визначає розмір загальної (shared) RAM-пам’яті для кешування, мінімальне значення дорівнює 8;

opcache.max_accelerated_files – встановлює максимальну кількість ключів для розширення, що визначає кількість сценаріїв для обробки. Мінімальне значення – 200, максимальне – 1000000;

opcache.revalidate_freq – встановлює значення часового інтервалу (у секундах) для перевірки оновлень міток часу сценарію;

opcache.validate_timestamps – включає перевірку сценаріїв у кешу на предмет їх оновлення через кількість секунд, визначених праметром opcache.revalidate_freq. У випадку відключення слід перезавантажити веб-сервер, щоб зміни почали діяти;

opcache.interned_strings_buffer – визначає розмір RAM-пам’яті (Mb) для зберігання інтернованих строк. Максимальні значення 32 767 і 4095 на 64-х та 32-х розрядних архітектурах відповідно;

opcache.enable – вмикає кеш, опцію не можна включити під час виконання коду, але можна відключити;

opcache.fast_shutdown – встановлює швидкий алгоритм припинення роботи, при котрому за швидке вивільнення пам’яті від наборів змінних відповідає стандартний менеджер пам’яті.

opcache.jit – керування режимами роботи JIT-компілятора за допомогою чотирьох строкових директив (function, tracing/on, off, disable). Значення tracing/on встановлене за замовчуванням та включає компілятор з компіляцією трейсів.

Є й інші важливі параметри, котрі можна знайти у документації PHP по використанню OPCache.

APCu – кеш даних в shared memory

Розширення APCu (APC User Cache) дає можливість кешувати у загальній пам’яті серверу дані додатків на рівні користувача. Це знижує потребу у застосуванні ресурснозатратних запитів до баз даних та мінімізує кількість операцій із файловою системою. Все це разом забезпечує економію машинних ресурсів та оптимізує продуктивність роботи додатку. Засіб найбільше підходить для оптимізації високонавантажених веб-додатків із високим рівнем трафіку, розміщених на локальних серверах. Підтримується для всіх версій препроцесору із діапазону PHP 5.5+.

Таким чином, можна виділити наступні переваги використання APCu: 

  • Дані знаходяться у RAM-пам’яті, що гарантує швидкий доступ та зчитування;

  • Дані доступні для запитів та процесів PHP;

  • Покращення масштабування додатку;

  • Зниження навантаження на базу даних;

  • Мінімізація операцій із файловою системою;

  • Простий API для керування записами кеша.

Встановлення та налаштування

Встановити розширення на ОС Mint/Debian/Ubuntu можна за допомогою наступної команди: 

# sudo apt install php-apcu

Після цього його необхідно увімкнути у файлі php.ini:

extension=apcu.so

Після перезавантаження веб-серверу у файл конфігурації config.php додатку ownClowd слід додати наступну строчку:

'memcache.local' => '\OC\Memcache\APCu',

Ця директива активує APCu для управління локальним кешем серверу.

Наведемо можливі значення основних параметрів APCu, котрі повинні бути присутніми у файлі php.ini:

apc.enabled=1
apc.ttl=1800
apc.shm_size=128M
apc.gc_ttl=800
apc.enable_cli=1
 
apc.enabled – вмикає розширення;
apc.ttl – задає час зберігання даних у секундах;
apc.shm_size – визначає розмір сегменту RAM-пам’яті;
apc.gc_ttl – задає часовий інтервал для очищення даних кеша ,котрі не використовуються;

apc.enable_cli – вмикає / вимикає APCu для CLI. За замовчуванням вимкнено, однак у подальшому можливі проблеми із виконанням завдань cron, і тому опцію краще увімкнути.

Використання

Бібліотека APCu надає широкі можливості для управління даними, котрі кешуються. Основними операціями є завантаження даних в кеш, їх отримання та видалення. Відповідні функції бібліотеки наведені нижче:

apcu_store();
apcu_fetch();
apcu_delete();
Приклад збереження в кеш:
$newdata = "This is an example of storing data in cache.";
$key = "one_key";
$ttl = 3600; // Дані кешуються на одну годину
apcu_store($key, $newdata, $ttl);

Приклад отримання даних із кеша:

$key = "one_key";
$data = apcu_fetch($key);
if ($data !== FALSE) {
echo "Data: " . $data;
} else {
echo "The requested data is not in the cache.";
}

Приклад очищення кеша:

function clearAllCache(): bool
{
return apcu_clear_cache();
}
clearAllCache();  // Забезпечує повне видалення всіх записів кеша

Наведемо приклад отримання статистичних даних по використанню пам’яті кеша за допомогою функції apcu_cache_info() бібліотеки APCu:

function getCacheInfo(): array
{
return apcu_cache_info();
}
// Вивід статистичних даних та коефіцієнтів потрапляння та відмов
print_r(getCacheInfo());

Redis – кеш даних + покращені можливості

У випадку розподілених багатосерверних додатків необхідно мати інструмент для розподіленого кешування структур даних незалежно від їх місцезнаходження. Розглянутий нами засіб APCu здатний забезпечити зберігання користувацьких даних лише у кешу локального сервера і тому тут не підходить.

Інструмент Redis призначений для використання у одно- та багатосерверних архітектурах додатків та немає прив’язки до локального кеша чи сховища. Він здатний забезпечити розподілене зберігання даних стільки часу, скільки потрібно, оскільки вони одразу записуються на диск, а не лише у кеш. Це, зокрема, дає можливість реалізувати транзакційне блокування файлів, чого не можна зробити за допомогою, наприклад, такого розповсюдженого кешера, як Memcached.   

Redis є PHP-модулем і тому потребує встановлення та налаштування. Рекомендована версія 2.2.6+.

Встановлення та налаштування

Встановити Redis на ОС Mint/Debian/Ubuntu можна за допомогою наступної команди:

# sudo apt install redis-server php-redis

Інсталятор модулю забезпечить автоматичний запуск redis-серверута налаштує його на запуск при кожному завантаженні системи.

Одразу після перезавантаження веб-серверу модуль буде готовий до використання.

Переконатися, що даемон Redis запущений в системі можна за допомогою відомої команди для формування списку запущених у Linux процесів:

# ps ax | grep redis

Вихід команди повинен бути приблизно наступним:

31215 ? Ssl0:00 /usr/bin/redis-server 127.0.0.1:6379

Якщо все  гаразд, слід перейти до наступного етапу – налаштування конфігурації Redis у файлі конфігурації config.php додатку ownClowd. Приклад таких налаштувань для випадку локального кеша серверу наведений нижче:

'memcache.local' => '\OC\Memcache\Redis',
'redis' => array(
 'host' => 'localhost',
 'port' => 6379,
 'timeout' => 0.0,
  ),

Тут підключення до кешу Redis здійснюється за протоколом TCP, що дещо уповільнює роботу з даними порівняно із APCu. І тому у випадку локального кешування краще налагодити Redis на прослуховування сокету Unix. Продемонструємо це, але перед тим слід виконати ряд підготовчих дій.

Додати користувача www-data до групи redis:

# sudo usermod -G redis -a www-data

Створити директорію для Unix-сокетів:

# sudo mkdir -p /var/run/myredis/

Встановити дозволи: 

# sudo chown -R redis:www-data /var/run/myredis

Внести зміни до файлу конфігурації Redis:

# створення сокету домену unix для прослуховування
unixsocket /var/run/myredis/redis.sock
# встановлення дозволів для сокету
unixsocketperm 770 

Зберегти внесені зміни та перезавантажити Redis-сервер.

Після цього залишається внести до файлу config.php наступні записи:

'filelocking.enabled' => true,
'memcache.locking' => '\OC\Memcache\Redis',
'memcache.local' => '\OC\Memcache\Redis',
'redis' => array(
 'host' => '/var/run/myredis/redis.sock',
 'port' => 0,
 'timeout' => 0.0,
  ),

Тепер швидкість обробки даних значно підвищиться. Таким чином можна покращити характеристики системи кешування відповідно до умов використання.

Сумісне використання різних систем кешування даних

При формуванні конфігурації системи кешування додатку слід врахувати ряд факторів, серед яких, зокрема, можна виділити наступні:

  • Додаток розподілений чи локальний;

  • Чи достатній об’єм RAM-пам’яті має сервер;

  • Чи потрібне транзакційне блокування файлів;

  • Чи є можливість та бажання використовувати кілька бекендів кешування.

Після формування відповідей на вказані питання, можливі наступні рішення по оптимізації системи кешування:

Для локальних систем із значним об’ємом загальної пам’яті може бути використаний засіб APCu. Це сприятиме високій швидкості роботи та простоті налагодження та експлуатації. Водночас з цим, для транзакційного блокування файлів слід застосувати Redis. Приклад відповідних налаштувань наведений нижче.

'filelocking.enabled' => true, //Включення транзакційного блокування файлів
'memcache.locking' => '\OC\Memcache\Redis',
'memcache.local' => '\OC\Memcache\APCu',
'redis' => [
'host' => 'localhost',
], 

При наявності обмежень на використання shared-пам’яті або у випадку необхідності або бажання мати лише один бекенд кешування найбільш доцільним варіантом буде Redis. Такийвибір пояснюється тим, що APCu додатково завантажить даними обмежені ресурси shared-пам’яті, чого не можна допустити.

У випадку бажання застосувати Redis без наявності розподіленого середовища кешування краще переналаштувати сервер на використання Unix-сокетів, як ми зробили раніше. Також слід виконати налаштування транзакційного блокування файлів. Цей варіант підійде для організації системи кешування у невеликій компанії із єдиним сервером у мережі. Відповідний код наведений нижче.

'filelocking.enabled' => true, //Включення транзакційного блокування файлів
'memcache.locking' => '\OC\Memcache\Redis',
'memcache.local' => '\OC\Memcache\Redis',
'redis' => [
'host' => '/var/run/myredis/redis.sock',
'port' => 0,
],

Для будь-якого розподіленого середовища кешування із можливістю доступу до даних інших хостів слід обрати Redis. Варіант підійде для великих компаній із розгалуженою мережевою структурою та кількома серверами. Приклад налаштувань для цього випадку наведений нижче.

'filelocking.enabled' => true,
'memcache.distributed' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'memcache.local' => '\OC\Memcache\APCu',
'redis' => [
'host' => '10.30.51.73', // IP-адреса хоста
    'host' => '15.35.55.71', 
    'host' => 'mainserver', // Ім’я серверу 
    'port' => 6379,
],

Слід зазначити, що у всіх наведених прикладах застосовується комбінація технологій: OPcache + APCu + Redis, оскільки OPcache, як вже зазначалося, входить до складу ядра препроцесору і не потребує додаткового включення. Це означає, що у нашому випадку кешування відбувається як на рівні коду (OPcache), так і на рівні даних (APCu + Redis), що забезпечує більш високий рівень продуктивності веб-додатку.

PHP-FPM – оптимальне налаштування процесів

PHP підтримує кілька режимів роботи, в тому числі і PHP-FPM (FastCGI Process Manager), котрий є найбільш вдалою реалізацією інтерфейсу FastCGI для препроцесора. Практика переконливо довела, що саме при поєднанні механізму кешування OPcache із режимом PHP-FPM можна досягти найвищих показників продуктивності при незмінності значень інших параметрів системи. Цьому сприяє, зокрема, те, що кожний процес PHP-пула використовує shared-пам’ять, що дозволяє йому мати доступ до даних, доданих іншими процесами.  

Режим PHP-FPM підтримує три стратегії управління дочірніми процесами:

  • Статичний (static);

  • Динамічний (dynamic);

  • «За вимогою» (ondemand).

Кожен з них по своєму корисний, виходячи із потреб та характеристик веб-додатку. Розглянемо кожен з них більш детально.

Статичний режим забезпечує наявність фіксованої кількості дочірніх процесів для обробки користувацьких запитів. Його включення та налаштування потрібної кількості процесів можна виконати за допомогою двох параметрів:

pm – вмикає режим

pm.max_children – вказує максимальну кількість процесів

Для Debian/Ubuntu такі налаштування можна зробити у файлі /etc/php/7.4/fpm/pool.d/www.conf

Режим може бути увімкнений для веб-ресурсу із значним рівнем трафіку, оскільки у такому разі буде забезпечене мінімальне значення параметру TTFB, а значить, користувачі вчасно отримають відповідь на свій запит.

Динамічний режим забезпечує регулювання кількості процесів для обробки запитів, гарантуючи при цьому наявність одного «вільного». Для управління ним задіяні наступні параметри:

  • pm.start_servers – кількість процесів на старті PHP;

  • pm.max_children – максимальна кількість процесів для запуску;

  • pm.process_idle_timeout – вказує час, скільки процес може «не працювати»;

  • pm.min_spare_servers – мінімальна кількість процесів, котрі «не працюють»;

  • pm.max_spare_servers – максимальна кількість процесів, котрі «не працюють».

Це найбільш універсальний режим за умови, якщо будуть правильно розраховані значення вказаних параметрів. Існують різні методики для їх розрахунку. Відповідно до однієї з них значення найбільш важливого параметру pm.max_children розраховується наступним чином:

(Загальний об’єм RAM) – (Об’єм для системних потреб ОС, БД тощо)/(Об’єм для одного  процесу) 

Для розрахунку розміру одного  процесу можна, наприклад, скористатися відомим Python-сценарієм, запустивши його на своїй машині. Також для з’ясування фактичних значень пам’яті, що використовується будь-яким запущеним процесом можна задіяти інструменти моніторингу, наприклад, php-memprof.

Режим може бути застосований для веб-ресурсів із значним трафіком, але при умові правильного розрахунку параметрів.

Режим Ondemand забезпечує створення нового процесу одразу при отриманні запиту. Його «головний» параметр:

pm.max_requests – визначає кількість запитів, котрі виконуються всіма процесами перед респауном.

Режим найбільше підходить для веб-ресурсів із малими значеннями трафіку, оскільки дозволяє економити такий ресурс, як пам’ять, оскільки процеси запускаються рідко і лише із появою запиту.

Оптимізація за допомогою пулів

Оптимізувати роботу додатку у режимі PHP-FPM також можна шляхом використання кількох пулів. Найбільш розповсюджений варіант – створити окремі пули для фронтенд та бекенд частин веб-ресурсу. У такому разі пули будуть належати одному і тому ж користувачу, але мати різні конфігурації менеджеру процесів, під’єднані через різні сокети. Наприклад, для фронтенд-частини можна включити «найшвидший» режим static, а для бекенду – ondemand. В результаті, відвідувачі магазину будуть отримувати швидку відповідь сервера, а Менеджери будуть мати невелику затримку при роботі із панеллю керування сайту, що є некритичним.

Для створення та налаштування пулів слід внести необхідні значення параметрів у конфігураційний файл: /etc/php/7.4/fpm/pool.d/www.conf, де налаштувати сокети для кожної з частин веб-ресурсу. Наприклад, для фронтенду запис у файлі буде виглядати наступним чином:

frontend [frontend] listen = /var/run/php-fpm-frontend.sock user = www-data group = www-data listen.owner = www-data listen.group = www-data pm = static pm.max_children = 7

Тут використано порівняно невелике значення параметру max_children, що необхідно для оптимізації витрати ресурсів.

Моніторинг

За допомогою status-сторінки FPM можна переглянути значення багатьох параметрів роботи. Вона вмикається шляхом встановлення параметру pm.status_path у конфігурації пула. Можна отримати вивід сторінки у різних форматах – json, xml та інших.

Наприклад, для текстового формату в адресній строчці браузера слід вказати:

https://localhost/fpm-status

Для формату json:

https://localhost/fpm-status?json

Зокрема, виводиться наступна інформація:

  • Загальна кількість прийнятих з’єднань;

  • Дата та час останнього запуску пулу процесів;

  • Загальна кількість процесів;

  • Кількість процесів, котрі на цей час обробляють запити;

  • Ім’я пула;

  • Детальна інформація про кожний процес:

    • Максимальний об’єм пам’яті, котрий був використаний останнім запитом;

    • Довжина тілу останнього запиту;

    • Загальна кількість запитів, що були обслуговуванні;

    • Стан процесу.

Використовуючи отримані дані можна зробити висновки про ефективність роботи додатку та підібрати оптимальні значення параметрів для покращення результатів.

Висновки

Як ми вже переконалися, для оптимізації роботи PHP-додатку недостатньо лише якогось одного з підходів, а потрібен комплексний підхід, котрий, зокрема, дозволить:

  • Знизити CPU-навантаження;

  • Організувати ефективне кешування на рівні коду та даних;

  • Встановити оптимальний режим роботи препроцесору.

Забезпечити це може лише інтеграцією технологій: OPcache + APCu + Redis + FPM, котрі ми тут коротко розглянули.

Практичне рішення від FREEhost.UA

Технічна підтримка дата-центру FREEhost.UA дбайливо допомагає користувачам з адмініструванням хмарних та фізичних серверів. Якщо Ви є користувачем наших послуг, ми завжди готові виконати для Вас аналіз роботи сервера, допомогти знайти вузькі місця у продуктивності та допомогти в усуненні проблеми. Дізнайтесь більше про послуги оренди серверів та хмарні сервери від дата-центру FREEhost.UA

Підписуйтесь на наш телеграм-канал https://t.me/freehostua, щоб бути в курсі нових корисних матеріалів.

Дивіться наш канал Youtube на https://www.youtube.com/freehostua.

Ми у чомусь помилилися, чи щось пропустили?

Напишіть про це у коментарях, ми з задоволенням відповімо та обговорюємо Ваші зауваження та пропозиції.

Дата: 12.07.2025
Автор: Олександр Ровник
Голосування

Авторам статті важлива Ваша думка. Будемо раді його обговорити з Вами:

comments powered by Disqus
navigate
go
exit
Дякуємо, що обираєте FREEhost.UA