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

Одним із популярних способів зменшення такого навантаження стало використання Memcached — високопродуктивної системи кешування даних в оперативній пам’яті.

У цьому історичному матеріалі розглядається встановлення Memcached і модуля PHP5-Memcached на Debian 6.0 Squeeze з вебсервером Apache2. Така конфігурація дозволяла PHP-застосункам тимчасово зберігати часто використовувані дані в оперативній пам’яті та повторно отримувати їх без звернення до повільніших джерел.

Debian 6.0, PHP5 і наведені назви пакетів давно застаріли та не повинні використовуватися на сучасному робочому сервері. Проте принципи роботи Memcached залишаються корисними для розуміння кешування, оптимізації вебзастосунків і зменшення навантаження на базу даних.

Що таке Memcached

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

Застосунок передає Memcached унікальний ключ і пов’язане з ним значення. Пізніше за цим самим ключем інформацію можна швидко отримати без повторного виконання складної операції.

У кеші можна зберігати:

результати SQL-запитів;

налаштування сайту;

сформовані частини сторінок;

списки категорій;

інформацію про товари;

результати обчислень;

тимчасові токени;

дані сесій;

відповіді зовнішніх API;

серіалізовані PHP-масиви та об’єкти.

Головною перевагою є швидкість оперативної пам’яті. Отримати невелике значення з Memcached зазвичай швидше, ніж виконувати складний SQL-запит, читати кілька файлів або повторно формувати велику частину HTML-сторінки.

Проте Memcached не є базою даних і не повинен використовуватися як єдине місце зберігання важливої інформації.

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

Як працює кешування

Типова схема роботи виглядає так:

користувач відкриває сторінку;

PHP формує ключ для потрібних даних;

застосунок перевіряє, чи є значення в Memcached;

якщо запис знайдений, дані одразу використовуються;

якщо запису немає, PHP звертається до бази даних;

отриманий результат зберігається в кеші;

наступні запити використовують уже підготовлене значення.

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

Якщо список оновлюється нечасто, його можна зберегти в Memcached на кілька хвилин. Тоді більшість користувачів отримуватиме вже готовий масив, а запит до бази виконуватиметься лише після завершення часу життя кешу.

Такий підхід називають cache-aside. Сам застосунок керує отриманням, створенням і оновленням кешованих даних.

Встановлення Memcached на Debian

В оригінальній конфігурації Memcached і модуль для PHP5 встановлювалися через пакетний менеджер APT.

Використовувалися пакети:

memcached;

php5-memcached.

Перед встановленням можна було виконати пошук доступних пакетів за словом memcache. У репозиторії Debian були присутні як php5-memcache, так і php5-memcached.

Попри схожі назви, це різні клієнтські розширення PHP.

Memcache — старіше розширення зі своїм API.

Memcached — інше розширення, яке працює через бібліотеку libmemcached і надавало ширший набір можливостей, включно з підтримкою серверних пулів і використанням Memcached для PHP-сесій.

В оригінальному матеріалі вибрано саме пакет php5-memcached.

Після встановлення служба Memcached зазвичай запускалася автоматично. Її стан можна було перевірити через список мережевих з’єднань.

За стандартною конфігурацією Memcached працював на локальному інтерфейсі та слухав порт 11211.

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

Налаштування служби

Основні параметри Memcached у Debian зберігалися у файлі:

/etc/memcached.conf

У ньому можна було налаштувати:

обсяг оперативної пам’яті для кешу;

мережеву адресу;

порт;

системного користувача служби;

максимальну кількість одночасних з’єднань;

журналювання;

режим запуску;

додаткові параметри мережі.

Один із найважливіших параметрів визначає, скільки пам’яті Memcached може використовувати.

Не слід віддавати кешу всю доступну оперативну пам’ять. Серверу також потрібні ресурси для операційної системи, Apache, PHP, бази даних та інших служб.

Якщо на машині мало пам’яті, занадто великий кеш може спричинити використання swap, падіння продуктивності або завершення важливих процесів.

Коли виділена пам’ять заповнюється, Memcached починає витісняти старі або давно не використовувані записи. Це нормальна частина його роботи.

Перезапуск Apache

Після встановлення PHP-модуля потрібно було перезапустити Apache2.

Нові розширення PHP не завжди підключаються до вже запущених процесів автоматично. Перезапуск вебсервера змушував Apache і PHP перечитати конфігурацію та завантажити модуль Memcached.

Після цього необхідно було переконатися, що розширення справді активне.

Перевірка через phpinfo

Для перевірки створювався тимчасовий PHP-файл із викликом функції phpinfo.

Сторінка phpinfo показувала:

версію PHP;

режим його запуску;

активні розширення;

шлях до конфігурації;

налаштування завантажених модулів;

ліміти пам’яті;

параметри сесій;

системну інформацію.

Якщо розширення встановлено правильно, на сторінці з’являвся окремий розділ Memcached.

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

Перше підключення з PHP

Для роботи з кешем у PHP створювався об’єкт класу Memcached.

Потім до клієнта додавався сервер кешування:

localhost;

порт 11211.

Після підключення PHP міг записувати та отримувати дані за ключами.

Найпростіший приклад виглядав так:

створити об’єкт Memcached;

додати локальний сервер;

записати значення hello world за ключем key;

отримати значення за тим самим ключем;

показати результат.

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

Приклад логіки кешування

Уявімо, що сайт отримує інформацію про популярні матеріали.

Спочатку PHP створює ключ:

popular_articles

Потім застосунок виконує запит до Memcached.

Якщо значення знайдено, список одразу передається шаблону.

Якщо значення відсутнє, виконується SQL-запит, після чого результат зберігається в кеші, наприклад, на п’ять хвилин.

Наступні користувачі протягом цього часу отримують готовий список без повторного сортування таблиці.

Умовний код може мати таку логіку:

підключитися до Memcached;

запросити значення за ключем;

перевірити код результату;

якщо кеш порожній — отримати дані з бази;

зберегти масив із часом життя;

повернути результат користувачеві.

Такий підхід особливо корисний для сторінок, які відкриваються часто, але їхній вміст оновлюється значно рідше.

Час життя запису

Під час збереження значення можна встановити термін його дії.

Після завершення цього часу запис вважається застарілим і більше не повертається застосунку.

Правильний час життя залежить від типу даних.

Наприклад:

налаштування сайту можна кешувати довше;

список останніх новин — кілька хвилин;

кількість непрочитаних повідомлень — короткий час;

курс валют — відповідно до частоти оновлення джерела;

результат важкого обчислення — залежно від допустимої актуальності.

Занадто короткий термін зменшує користь кешу, оскільки дані постійно створюються заново.

Занадто довгий термін може призвести до показу застарілої інформації.

Очищення кешу після змін

Не завжди потрібно чекати завершення встановленого часу.

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

Це називається інвалідацією кешу.

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

latest_articles;

popular_articles;

category_articles_technology;

homepage_articles.

Після редагування профілю користувача можна очистити кеш його публічних даних.

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

Правильне формування ключів

Ключі повинні бути зрозумілими та однозначними.

Поганий варіант:

data1

Кращий варіант:

article_25;

user_profile_14;

news_category_technology_page_2;

community_my-dark-master_stats.

У ключ можна додавати версію:

news_list_v2_page_1

Якщо структура даних у програмі змінилася, достатньо збільшити версію ключа. Старі записи поступово будуть витіснені, а застосунок почне використовувати новий формат.

Не слід включати в ключі паролі, токени або іншу секретну інформацію.

Кешування результатів SQL-запитів

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

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

Якщо виконувати таку операцію для кожного відвідувача, база даних отримуватиме значне навантаження.

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

Проте не всі запити потрібно кешувати.

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

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

Кешування HTML

У Memcached можна зберігати не лише масиви, а й готові фрагменти HTML.

Наприклад:

блок популярних новин;

меню категорій;

список коментарів;

бічну панель;

віджет статистики;

підготовлену картку матеріалу.

Під час першого запиту PHP формує блок через шаблон, а потім зберігає готовий HTML.

Наступні відвідувачі отримують уже сформований результат.

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

Сесії в Memcached

Розширення PHP5-Memcached підтримувало збереження PHP-сесій у Memcached.

Це могло бути корисним для систем із кількома вебсерверами. Користувач надсилав запит на будь-який вузол, а всі сервери працювали зі спільним сховищем сесій.

Проте таке рішення має ризики.

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

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

Кілька серверів Memcached

Для великих проєктів можна створити пул із кількох серверів.

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

Якщо один сервер має більше ресурсів, йому можна призначити більшу вагу.

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

Водночас Memcached не є автоматичною системою резервного копіювання. Якщо конкретний вузол зникає, записи, що зберігалися на ньому, можуть стати недоступними.

Застосунок повинен сприймати це як звичайний промах кешу та відновити дані з основного джерела.

Захист Memcached

Одна з найважливіших вимог — не відкривати Memcached для всього інтернету.

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

Для односерверної системи найкраще слухати лише:

127.0.0.1

Якщо кеш розміщений на окремій машині, доступ потрібно обмежувати міжмережевим екраном до конкретних IP-адрес вебсерверів.

Також потрібно вимкнути непотрібний UDP, контролювати відкриті порти та не зберігати в кеші секрети у відкритому вигляді.

Компрометація Memcached може дозволити сторонній особі читати, змінювати або видаляти тимчасові дані застосунку.

Кеш не повинен містити незахищені паролі, приватні ключі, повні банківські реквізити або інші критичні секрети.

Проблема масового оновлення

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

Це явище називають cache stampede.

Замість одного складного SQL-запиту сервер раптово отримує сотні або тисячі однакових операцій.

Для боротьби з цим використовують:

блокування на час оновлення;

випадкове відхилення терміну життя;

попереднє оновлення популярних записів;

збереження старого значення на короткий період;

фонове формування кешу.

Навіть проста система кешування повинна враховувати, що одночасні користувачі можуть звернутися до одного ключа.

Коли кешування не допомагає

Memcached не прискорює сайт автоматично після встановлення.

Застосунок потрібно окремо запрограмувати для запису, отримання та очищення кешу.

Кешування може не дати користі, якщо:

дані майже ніколи не запитуються повторно;

операція і так виконується дуже швидко;

значення змінюється після кожного запиту;

обсяг даних занадто великий;

підключення до кешу повільніше за основну операцію;

застосунок неправильно очищає застарілі значення.

Також не варто кешувати все без розбору. Надмірна кількість ключів ускладнює підтримку системи та може призвести до показу неактуальної інформації.

Спочатку потрібно знайти реальне вузьке місце: повільний SQL-запит, складний розрахунок, зовнішній API або важкий шаблон. Лише після цього варто додавати кеш.

Моніторинг

Після запуску Memcached потрібно контролювати його роботу.

Корисно стежити за такими показниками:

кількість успішних отримань;

кількість промахів кешу;

використана пам’ять;

кількість витіснених записів;

активні з’єднання;

загальна кількість команд;

час роботи служби;

помилки підключення.

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

Якщо постійно зростає кількість витіснень, кешу може не вистачати виділеної пам’яті.

Проте збільшувати ліміт потрібно лише після перевірки, що сервер має достатньо вільної оперативної пам’яті.

Сучасне використання

Оригінальний матеріал описував Debian 6.0 Squeeze, Apache2 і PHP5. Ці версії завершили підтримку та містять відомі вразливості.

Для сучасного проєкту потрібно використовувати підтримувану версію Debian, актуальний PHP і нову версію клієнтського розширення Memcached.

Також необхідно:

обмежити службу локальною мережею;

закрити порт міжмережевим екраном;

вимкнути непотрібні протоколи;

регулярно оновлювати пакети;

налаштувати моніторинг;

правильно обробляти недоступність кешу;

не використовувати Memcached замість постійної бази даних.

Принцип роботи при цьому не змінюється: застосунок спочатку шукає дані у швидкому кеші, а в разі відсутності отримує їх із надійного основного сховища.

Підсумок

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

В історичній конфігурації для Debian 6.0 встановлювалися служба memcached і модуль php5-memcached. Після перезапуску Apache робота розширення перевірялася через phpinfo, а PHP підключався до локальної служби на порту 11211.

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

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

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