Чотири рівні кешування в мережі клієнтський, мережевий, серверний та рівень програми

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

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

  • клієнтська;
  • мережевий;
  • серверний;
  • рівень програми.

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

Кеш на клієнтському рівні

Заголовки HTTP відповідають за визначення можливості кешування відповіді та визначення терміну зберігання даних. Наступний приклад заголовка Cache-control показує, що відповідь може перебувати у кеші протягом 7 днів. Браузер надішле повторний запит на зберігання даних, якщо термін зберігання спливе або користувач цілеспрямовано оновить сторінку.

Запит та відповідь, які можуть бути кешовані протягом 604 800 секунд.

Відповідь також може містити заголовок Last-Modified або Etag. Ці заголовки потрібні для перевірки можливості повторного використання даних. Статус відповіді 304 вказує на те, що вміст не змінився і повторне завантаження не потрібно. Зверніть увагу на парні заголовки Last-Modified та If-Modified-Since, а також на дати нижче:

Відповідь із заголовком «Last-Modified» та наступним запитом з йоговикористанням.

Заголовок Etag використовується з If-None-Match аналогічно для обміну кодами відповіді при визначенні змін у контенті, якщо вони є.

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

Кеш на мережному рівні

Згідно з Вікіпедією, Мережа Доставки Контенту (CDN) — географічно розподілена мережева інфраструктура, що дозволяє оптимізувати доставку та дистрибуцію контенту кінцевим користувачам в Інтернеті. Іншими словами, CDN - це розподілене зберігання та використання кешу.

Директива HTTP-заголовка Cache-control: public дозволяє різним частинам мережі кешувати відповідь. За допомогою заголовка Cache-Control: public, max-age=31536000 знаходять ресурси, що зберігаються протягом одного року.

Можливо ви вже знайомі з іншими директивами заголовків. Існує також ще один потужний заголовок для обробки автентифікованих та інших видів динамічних відповідей.

Кеш на серверному рівні

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

Перший підхід до більш швидких відповідей та економії ресурсів – налаштування кеш-сервера між програмою та клієнтом.

Клієнти, що запитують один і той же вміст на проксі-сервері.

Такі інструменти, як Varnish, Squid та nginx кешують зображення, скрипти та інший вміст, який потрібний користувачам. Наступне налаштування nginx збирає кеш, спираючись лише на HTTP-заголовки у додатку.

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

Безліч клієнтів, що запитують один і той же вміст одночасно.

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

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

Посібник з кешування з NGINX та NGINX Plus містить докладнішу інформацію та параметри конфігурації.

Кеш на рівні програми

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

Мемоізація

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

Цю функцію можна викликати із будь-якого місця коду. Однак використання такої техніки викликає певні проблеми. Важливо пам'ятати, що ваші дані не матимуть терміну актуальності. Тобто глобальна мемоізація коду залишатиметься у пам'яті протягом усього циклу роботи програми.

Інтелектуальне кешування у пам'яті

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

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

Спільне кешування

Вміння поводитися з зростаючою кількістю користувачів та запитів – важливий об'єкт веб-розробки. Один із способів масштабування програми – додавання екземплярів програми (горизонтальне масштабування). Як ви, мабуть, здогадалися, простий кеш у пам'яті не може використовуватися кількома екземплярами.

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

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

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

Запобігання стану гонки для кешу з кількома екземплярами додатків є складним завданням. Оптимальним рішенням у цьому випадку є оновлення даних кешу поза потоком програми та використання кешованих даних у самому додатку. В архітектурі мікросервісу можна захистити зв'язок між додатком та сервісом за допомогою nginx, як описано вище.

Висновок