1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6

# конспект · шаг 6 из 6

Конспект: кеш ответов бэкенда

выжимка - её можно унести в заметки

Кеш ответов бэкенда: две сущности, три таймера и одна ловушка с ключом.

Устройство

# зона в памяти + файлы на диске
proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=API:10m
                 inactive=60m max_size=2g;

location /api/ {
    proxy_cache API;
    proxy_cache_valid 200 302 10m;    # успешные - на 10 минут
    proxy_cache_valid 404      1m;    # отрицательные - чтобы не долбить бэкенд
    proxy_pass http://app:8000;
}

Без proxy_cache_valid кеш не работает - nginx не знает, сколько ответ считать свежим (если бэкенд сам не прислал Cache-Control).

Три таймера, которые путают

Параметр Смысл
proxy_cache_valid сколько ответ считается свежим
inactiveproxy_cache_path) сколько запись живёт без обращений
max_size сколько всего места под кеш

Запись с valid 10s и inactive 60m протухнет через 10 секунд, но останется на диске - и пригодится, когда бэкенд ляжет. И наоборот: популярная страница с valid 1h вылетит из кеша, если к ней час никто не пришёл.

Что должно быть в конфиге кеша

proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_min_uses 2;                     # не кешировать одиночные запросы
proxy_cache_bypass $http_pragma $cookie_session;   # когда НЕ отдавать из кеша
proxy_no_cache     $cookie_session;                # когда НЕ класть в кеш
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
proxy_cache_lock on;                        # набег на истечении - один запрос к бэкенду
proxy_cache_background_update on;
add_header X-Cache-Status $upstream_cache_status always;

Ловушки джокера

  • Ключ с $uri вместо $request_uri отбрасывает строку запроса: ?page=2 и ?page=3 получат один и тот же ответ.
  • Кеширование персональных ответов. Без пары bypass + no_cache чужая корзина уедет соседнему пользователю - это самая дорогая ошибка раздела.
  • Set-Cookie от бэкенда отключает кеширование ответа; если это мешает - убирают заголовок осознанно, а не «чтобы заработало».
  • Баг связки proxy_cache_revalidate с HTTP/2-бэкендом починен в 1.31.3.

Что показал стенд

опыт результат
proxy_cache без proxy_cache_valid три MISS подряд, три обращения к бэкенду
с proxy_cache_valid 200 10s MISS, HIT, HIT - одно обращение
бэкенд прислал Cache-Control: max-age=60, valid не задан MISS, HIT - кеш работает от заголовка
ответ с Set-Cookie или no-store MISS, MISS - не кешируется
ключ по $uri, запрос ?page=2 HIT с содержимым ?page=1
proxy_cache_min_uses 3 MISS, MISS, MISS, HIT
бэкенд остановлен, use_stale против его отсутствия 200 STALE против 502 EXPIRED
десять одновременных запросов на пустой ключ, ответ 2 с без cache_lock 10 обращений, с ним 1
прогретый кеш, перезапуск nginx запись остаётся HIT - кеш переживает рестарт

Ловушки джокера

  • proxy_cache без proxy_cache_valid не кеширует ничего - и это первая ловушка при знакомстве.
  • Срок задаётся в двух местах: заголовок бэкенда работает сам, поэтому приложение может незаметно переопределить конфиг в обе стороны.
  • Сокращённый ключ склеивает разные страницы в одну запись, и в логе при этом честный HIT.
  • bypass без no_cache отправляет авторизованного мимо кеша, но его личный ответ туда всё равно запишется.
  • proxy_ignore_headers Set-Cookie без proxy_hide_header Set-Cookie раздаёт чужую сессию всем.
  • Кончается зона ключей, а не диск: 10 МБ - это около 80 тысяч записей.
  • use_stale не спасает то, чего в кеше нет - перед выкладкой кеш греют.
  • proxy_cache_lock - про новые записи; набег на протухшую закрывают updating в use_stale плюс background_update.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.