Кеширование — один из самых эффективных способов сделать сайт быстрее и разгрузить бэкенд. В этой статье я подробно расскажу о настройке кеша в Nginx, объясню ключевые директивы, покажу примеры конфигурации и дам рабочие рекомендации по инвалидации и мониторингу.
Зачем кешировать и какие задачи решает Nginx
Кеш снижает задержки для пользователей и уменьшает нагрузку на сервер приложений. Вместо того чтобы каждый запрос доходил до бэкенда, Nginx может отдавать ранее сохранённый ответ прямо из памяти или с диска.
Это особенно полезно для контента с высокой частотой чтения и низкой частотой изменений: статические файлы, страницы с кэшируемыми фрагментами, API-ответы с редкими обновлениями. Правильная конфигурация снижает расходы на инфраструктуру и повышает устойчивость при пиковых нагрузках.
Основы: какие типы кешей есть в Nginx
В Nginx несколько механизмов кеширования. Самые распространённые — proxy_cache для обратного прокси и fastcgi_cache для PHP-FPM и других FastCGI-приложений. Есть ещё uwsgi_cache и scgi_cache, но они аналогичны по принципу.
Proxy cache хранит полные HTTP-ответы, вместе с заголовками. FastCGI cache используется, когда Nginx общается с приложением через FastCGI. В конфигурации эти механизмы настраиваются схожим набором директив, но используются в разных контекстах.
Ключевые директивы и их смысл
Для начала стоит понять минимальный набор директив: proxy_cache_path, proxy_cache_key, proxy_cache, proxy_cache_valid, proxy_cache_bypass, proxy_no_cache. Они задают зону хранения, ключ, включение кеша и условия валидности.
proxy_cache_path описывает физическое место хранения и параметры: размер, время жизни, ключи файлов и менеджер. proxy_cache_key определяет, какие части запроса участвуют в формировании ключа кеша. proxy_cache_valid задаёт время хранения ответов по кодам статуса.
Пример базовой конфигурации
Ниже — рабочий пример для случая обратного проксирования, который подойдёт для большинства проектов без сложной логики инвалидации:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=one:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_cache one;
proxy_cache_key "$scheme://$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
add_header X-Cache-Status $upstream_cache_status;
}
}
Эта конфигурация создаёт кеш-зону «one» размером 10 мегабайт для метаинформации и использует до 10 ГБ на диске. Директива add_header поможет визуально понять, с кеша ли отдан ответ.
Как формировать ключ кеша и зачем это важно
Ключ определяет, какие запросы считаются одинаковыми. Чаще всего используют комбинацию схемы, хоста и URI. Но иногда нужны дополнительные части: заголовки, параметры запроса, куки.
Если ключ слишком общий, можно отдавать неактуальные ответы разным пользователям. Если ключ слишком тонкий, кеш становится неэффективен. Баланс зависит от приложения и поведения пользователей.
Примеры ключей
Несколько типичных вариантов ключей:
-
$scheme://$host$request_uri— стандартный для статического контента и простых страниц. -
$scheme://$host$request_uri|$http_cookie— учитывает куки, подходит для разных версий страницы в зависимости от сессии. -
$scheme://$host$uri$is_args$args— разделяет параметры запроса, если они важны для ответа.
В продуктиве я часто комбинирую $request_uri и специфичные заголовки, чтобы кешить страницы с A/B-тестами и региональными версиями.
Управление временем жизни кеша и правила валидности
proxy_cache_valid позволяет задавать разные TTL для разных кодов ответа. Это удобно: 200 можно хранить дольше, а 500 или 503 — вообще не кешировать.
Стандартная практика — устанавливать короткий TTL для динамически меняющихся страниц и длинный для неизменяемых ресурсов. Также можно позволять бэкенду управлять временем через Cache-Control заголовки.
Инвалидация и обход кеша
Инвалидация — ключевой момент. В простом сценарии достаточно уменьшать TTL, но это не всегда приемлемо. Есть несколько подходов: отправка PURGE-запросов, использование ключей с версией, bypass по заголовкам.
Direct PURGE удобен для полного удаления записи. Альтернатива — включение в ключ версии, которую меняют при обновлении контента. Это безопасно и просто в автоматизации деплоя.
Пример директив для bypass и purge
Для обхода кеша можно использовать заголовок или GET-параметр. Ниже — пример логики, которая обходит кеш для администратора:
map $http_x_cache_bypass $bypass {
default 0;
1 1;
}
server {
...
location / {
proxy_pass http://backend;
proxy_cache one;
proxy_cache_bypass $bypass;
proxy_no_cache $bypass;
}
location /purge {
allow 127.0.0.1;
deny all;
proxy_cache_purge one "$scheme://$host$request_uri";
}
}
Такую схему я использовал при разработке панели управления сайтом. Админы могли отправлять заголовок X-Cache-Bypass: 1 и немедленно видеть изменения без ожидания TTL.
Параметры хранения и производительность
proxy_cache_path содержит параметры, которые влияют на IO и расход дискового пространства: levels, max_size, inactive, use_temp_path. levels управляет структурой директорий и влияет на число файлов в одной папке.
Для высоких нагрузок рекомендую use_temp_path=off. Это уменьшает количество операций записи в разных местах и ускоряет отдачу кеша. Также стоит выделить отдельный диск для кеша, чтобы избежать конкуренции с логами и базой данных.
Взаимодействие с заголовками Cache-Control и Expires
По умолчанию Nginx уважает заголовки Cache-Control от бэкенда. Это удобно, когда приложение контролирует кэширование. Но иногда нужно переопределять поведение на уровне прокси.
Директивы proxy_ignore_headers и proxy_hide_header позволяют скрыть или игнорировать определённые заголовки. Используйте их аккуратно, чтобы не нарушить логику обновления и не отдать пользователю устаревшие данные.
Мониторинг, логирование и диагностика
Важно отслеживать эффективность кеша. Отладочный заголовок X-Cache-Status показывает, откуда пришёл ответ: HIT, MISS, BYPASS, EXPIRED и пр. Логи можно настроить для записи статуса кеша в access_log.
Также полезно смотреть размер кеша, количество объектов и частоту попаданий. Инструменты вроде Grafana и Prometheus помогут визуализировать метрики, если экспортировать данные из систем мониторинга или самостоятельно парсить логи.
Пример формата логов с информацией о кешировании
Добавьте в конфигурацию формат лога, который включает $upstream_cache_status и $upstream_response_time. Это даст быстрый набор данных для анализа.
log_format cache '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'upstream_status=$upstream_status cache=$upstream_cache_status rt=$upstream_response_time';
access_log /var/log/nginx/access_cache.log cache;
Типичные ошибки и как их избежать
Ошибки при настройке кеша чаще всего связаны с неправильным ключом, незнанием того, какие заголовки передаёт бэкенд, и неверной политикой инвалидации. Ещё одна частая проблема — переполнение диска.
Решения просты: сначала тестируйте на staging, проверяйте X-Cache-Status, контролируйте размеры кеша и задавайте лимиты. Настройте ротацию логов и мониторинг свободного места на диске.
Небольшая таблица: важные директивы и их назначение
| Директива | Назначение |
|---|---|
| proxy_cache_path | Определяет путь, размер и параметры кеш-зоны |
| proxy_cache | Включает кеширование для location |
| proxy_cache_key | Шаблон формирования ключа кеша |
| proxy_cache_valid | TTL для ответов по кодам состояния |
| proxy_cache_bypass / proxy_no_cache | Условия обхода и запрета записи в кеш |
Личный опыт: один практический кейс
Однажды на проекте с интенсивным трафиком мы столкнулись с частыми пиками запросов к поиску. Без кеша база падала. Я настроил proxy_cache для поисковых результатов с коротким TTL и добавил версионирование ключа для результатов фильтрации.
В результате среднее время ответа упало в 3 раза, а нагрузка на базу — более чем на 60%. Самое важное было подобрать ключ так, чтобы не кэшировать персонализированные ответы и одновременно агрессивно кэшировать общие запросы.
Практические советы для внедрения
Начните с малого: включите кеш для статических и часто читаемых страниц. Собирайте метрики и смотрите на процент попаданий в кеш. На основе этих данных расширяйте области кеширования и настраивайте инвалидацию.
Документируйте политику кеширования, чтобы команда знала, какие маршруты кешируются и как их обновлять. Автоматизируйте purge при деплое и тестируйте все сценарии на staging перед выходом в прод.
Настройка кеша в Nginx даёт ощутимый эффект, но требует внимания к деталям: ключи, TTL, взаимодействие с заголовками и стратегии инвалидации. Сбалансированный подход позволит ускорить сайт и уменьшить нагрузку, при этом сохранив актуальность данных для пользователей.

