ЛубниЛубни // 2010-08-21

Інвалідація кешу на Веб-сайті

Існують дві основні проблеми компʼютерних наук:

  • Інвалідація кешу
  • Вибір імені змінної
  • Помилка на одиницю

Другу та третю я поки для себе остаточно не вирішив, а от з першою наче розібрався в контексті веб-розробки.

В чому суть?

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

Це означає, що усі «статичні» файли повинні мати HTTP заголовок, подібний до цього:
Cache-Control: public, max-age=31536000 (файл публічний, може бути закешований на термін до року)

Уявімо, що це основний CSS файл сайту, і нам дуже потрібно змінити деякі стилі. Редагуємо файл, компілюємо у випадку Sass або Less, завантажуємо на сервер (або розгортаємо з репозиторію), оновлюємо сторінку в браузері і не бачимо ніяких змін. Причина проста — ми ж самі вказали, що файл можна кешувати на тривалий термін, який ще не минув. У випадку з CDN не допоможе навіть очищення кешу браузера.

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

Варіанти рішень

Проблема вирішується, якщо до адреси файлу додати якийсь параметер, наприклад номер версії:
/assets/css/styles.css?v=2
Але в цьому випадку деякі браузери та CDN не будуть вважати цей файл «статичним» і не покладуть в кеш на тривалий період. Також потрібно мати якусь систему для управління версіями (міняти версію вручну не дуже зручно).

Трохи кращим способом вирішення цієї проблеми є налаштування веб-серверу так, щоб він ігнорував частину шляху до файлу. Для прикладу, будь-яке посилання, подібне до цього:
/assets/5bb64bbfb766/css/styles.css
буде вказувати на той самий файл:
/assets/css/styles.css
Це легко зробити в багатьох веб-серверах, для прикладу Nginx:
rewrite ^/assets/([0-9a-f]+)/(css|img|js)/(.*)$ /assets/$2/$3 break;

Залишається визначити, звідки взяти номер версії (v=2) або інвалідатор кешу (5bb64bbfb766).

На сайті, що використовується виключно для тестування, дуже зручно використовувати щось подібне до 20200829000000 або 1598659200 тобто поточний час з точністю до секунди. Це фактично вимикає кеш і будь-які зміни зʼявляються на сайті миттємо.

На сайті, що розгортається з репозиторію, зручно використовувати ідентифікатор останнього коміту.
Для git та гілки master поточне значення знаходиться в цьому файлі:
.git/refs/heads/master
Як саме його використовувати залежить від CMS/фреймворку, репозиторію, методу розгортання і т.п.

Найбільш оптимальним є використання часу останньої модифікації конкретного файлу або його хеш (md5, sha1). Але повноцінна реалізація цього підходу буде коштувати більше часу та зусиль ніж попередній варіант. Хоча якщо у вас тисячі статичних файлів а скидання кешу для усіх одразу є дорогою операцією, то в цьому є сенс.

На останок

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

На роботі я використовую такий самий підхід, хіба в деяких старих проектах це параметр а не частина шляху. Більше ніяких відмазок співробітникам типу «на моєму компʼютері все добре» та «будь ласка, очистіть кеш браузера».