Модуль 20

Кешування в Nginx

Ось урок, створений у стилі CS50 — енергійно, з аналогіями та фокусом на розумінні суті.


🎓 CS50: Кешування в Nginx

(Тема: Як не змусити сервер померти від перевтоми)


1. 🔥 Вступ: Проблема піци та черги

Уявіть, що ви власник найпопулярнішої піцерії в місті. У вас є геніальний шеф-кухар (назвемо його Backend). Він робить найкращу піцу "Маргарита", але на приготування однієї йде рівно 10 хвилин.

Ось заходить 100 клієнтів, і всі вони замовляють "Маргариту". Що робить ваш шеф? Він починає готувати першу... другу... На десятій він втомлюється, на п’ятдесятій — кухня палає, а сотий клієнт отримає своє замовлення завтра вранці.

Питання до вас: Чи є сенс готувати кожну з цих 100 піц з нуля, якщо вони абсолютно однакові?

Звісно, ні!

Якби ви (як менеджер, або Nginx) були розумнішими, ви б зробили так: 1. Шеф готує першу піцу. 2. Ви кладете 99 таких самих піц під теплову лампу (у "кеш"). 3. Наступні 99 клієнтів отримують замовлення миттєво. Шеф відпочиває і п’є каву.

Сьогодні ми говоримо про Кешування в Nginx. Без нього будь-який серйозний сайт впаде під навантаженням (так званий "Хабраефект" або Reddit hug of death). Ми навчимося зберігати готові відповіді сервера, щоб віддавати їх клієнтам за мілісекунди.


2. 🧠 Теоретична база (Що там під капотом?)

Перш ніж писати код, зрозуміємо механіку.

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

  1. Запит: Клієнт просить сторінку /home.
  2. Перевірка (Lookup): Nginx дивиться у свій кеш (папку на диску). "Я вже бачив цей запит?"
  3. MISS (Промах): Якщо ні — він йде до бекенду (PHP, Python, Node.js), чекає відповідь, зберігає її копію собі на диск і віддає клієнту.
  4. HIT (Влучання): Якщо так — він навіть не турбує бекенд! Він просто бере файл з диска і кидає його клієнту.

🔑 Ключові поняття (запам'ятати):

  • Cache Path: Місце на диску, де лежать файли кешу.
  • Keys Zone: Область у пам'яті (RAM), де Nginx зберігає "список вмісту" (метадані) — щоб знати, де який файл лежить, не скануючи диск постійно.
  • Cache Key: Унікальний ідентифікатор запиту. Зазвичай це комбінація host + uri. Якщо ключ збігається — віддаємо кеш.
  • Validity: Термін придатності. Як довго піца під лампою лишається свіжою? 1 хвилину? 1 годину?

Інтуїтивно: Кеш — це короткочасна пам'ять вашого сервера. Вона швидка, але не вічна.


3. 🧪 Приклади (Від "Hello World" до PRO)

Давайте налаштуємо це. Уявіть, що у нас є повільний бекенд на порту :3000.

Приклад 1: Базове налаштування

Спочатку ми маємо сказати Nginx, де зберігати кеш. Це робиться в контексті http (глобально), а використовується вже в location.

http {
    # 1. Створюємо зону для кешу
    # path: куди зберігати файли
    # levels: структура папок (щоб не звалити все в одну купу)
    # keys_zone: назва зони (my_cache) і розмір пам'яті для ключів (10mb)
    # inactive: видалити, якщо ніхто не питав про це 60 хвилин
    proxy_cache_path /var/cache/nginx/my_cache levels=1:2 keys_zone=my_cache:10m inactive=60m;

    server {
        listen 80;

        location / {
            # 2. Вмикаємо кешування для цього location
            proxy_cache my_cache;

            # 3. Визначаємо правила: 
            # Відповіді з кодом 200 і 302 кешуємо на 10 хвилин
            proxy_cache_valid 200 302 10m;

            # 4. Що робити, якщо бекенд впав?
            # Віддай старий кеш, навіть якщо він прострочений! (Stale cache)
            proxy_cache_use_stale error timeout updating;

            proxy_pass http://localhost:3000;
        }
    }
}

Що ви очікуєте побачити? Перший запит буде повільним (MISS). Другий — миттєвим (HIT).

Приклад 2: Додаємо прозорість (Header)

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

location / {
    proxy_cache my_cache;
    proxy_cache_valid 200 10m;
    proxy_pass http://localhost:3000;

    # Додаємо заголовок X-Cache-Status
    add_header X-Cache-Status $upstream_cache_status;
}

Тепер, якщо ви зробите curl -I http://site.com, ви побачите: X-Cache-Status: MISS (перший раз) X-Cache-Status: HIT (другий раз)


4. 🛠 Практична частина

Час "забруднити руки". Якщо у вас немає під рукою сервера, уявіть ці дії або запустіть локальний Docker-контейнер з Nginx.

Завдання 1: Налаштуй та перевір Створіть конфіг із прикладу вище. Зробіть два запити curl. Питання: Чи змінився час відповіді? Чи з'явився заголовок HIT?

Завдання 2: "Аварійний режим" Вимкніть ваш бекенд (зупиніть процес на порту 3000). Зробіть запит до Nginx. Завдання: Налаштуйте proxy_cache_use_stale, щоб Nginx віддав стару версію сторінки замість помилки 502 Bad Gateway. Чому це круто: Користувачі навіть не помітять, що ваш бекенд "лежить".

Завдання 3: Винятки (Bypass) Іноді вам, як розробнику, треба бачити свіжу версію, ігноруючи кеш. Додайте:

proxy_cache_bypass $http_my_secret_header;

Тепер зробіть запит: curl -H "my-secret-header: true" http://site.com. Ви маєте отримати MISS (свіжі дані), навіть якщо в кеші є копія.

Завдання 4: Міні-кейс У вас є сторінка новин (/news), яка оновлюється раз на годину, і стрічка коментарів (/comments), яка оновлюється щосекунди. Задача: Напишіть два location блоки з різним часом proxy_cache_valid.


5. 💡 Мислення як у розробника

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

⛔ Типова помилка: Кешування приватних даних

Уявіть, що Вася залогінився і бачить "Привіт, Вася!". Nginx закешував цю HTML-сторінку. Тепер заходить Петро... і Nginx радісно віддає йому кеш: "Привіт, Вася!". Катастрофа. Петро бачить особисті дані Васі.

Як думає профі:

"Я ніколи не кешую сторінки, де є сесії або персоналізація, на рівні Nginx, якщо не налаштував унікальний proxy_cache_key (наприклад, з урахуванням Cookie). А краще — кешувати лише статику та публічні API, а динаміку лишати бекенду."

💡 Порада: Ігнорування заголовків

Бекенди часто самі надсилають заголовки Cache-Control: no-cache. Nginx за замовчуванням поважає їх і не кешує. Якщо ви хочете змусити Nginx кешувати попри все, використовуйте:

proxy_ignore_headers Cache-Control Expires;

Використовуйте це обережно!


6. 🧩 Підсумок

Ми з вами щойно врятували сервер від перевантаження.

Що ви тепер вмієте: 1. Створювати зону для кешу на диску. 2. Налаштовувати час життя кешу для різних відповідей. 3. Налаштовувати відмовостійкість (віддавати старий контент, якщо бекенд впав). 4. Розумієте різницю між MISS та HIT.

Тизер наступного уроку: Окей, ми кешуємо, сервер працює швидко. Але що, якщо один сервер Nginx вже не справляється з трафіком навіть із кешем? Нам потрібно більше серверів! На наступному уроці ми поговоримо про Load Balancing (Балансування навантаження) — як змусити кілька серверів працювати як один злагоджений механізм.

А поки що — це був CS50! 👋