Введение: зачем управлять кэшем proxy_cache
Nginx proxy_cache кэширует ответы бэкенда и отдаёт их пользователям без повторного обращения к приложению. Это снижает задержку, уменьшает нагрузку на upstream и ускоряет доставку контента. Проблема возникает, когда данные на бэкенде обновились, а Nginx продолжает отдавать старый ответ из кэша. Пользователь видит устаревшую информацию, API возвращает неактуальные данные, а интернет-магазин показывает старую цену.
Решение - управляемая инвалидация кэша. Есть три основных подхода: полная очистка всей кэш-директории, выборочная очистка через purge-зону с модулем ngx_cache_purge и автоматическая инвалидация при обновлении данных. В этой статье разобраны все три метода с рабочими конфигурациями, командами и предупреждениями о рисках.
Для базовой настройки кэширования рекомендую сначала изучить полное руководство по proxy_cache, а для точечной очистки по URL и regex - материал по ngx_cache_purge.
Основы proxy_cache: где хранится кэш и как им управлять
Прежде чем очищать кэш, нужно понимать, где он лежит и как идентифицируются записи. Это определяет, какие команды безопасны, а какие приведут к ошибкам 502.
Директива proxy_cache_path: параметры и пример
Директива proxy_cache_path задаёт путь к файлам кэша, структуру каталогов, размер зоны ключей и лимиты хранения. Базовая конфигурация:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;Разбор параметров:
- /var/cache/nginx - корневая директория кэша. Именно здесь Nginx создаёт файлы с ответами бэкенда.
- levels=1:2 - иерархия подкаталогов. Первый уровень - один символ, второй - два символа. Это ускоряет поиск файлов на файловой системе при большом количестве записей.
- keys_zone=my_cache:10m - имя зоны и размер разделяемой памяти для хранения ключей и метаданных. Зона в 10 МБ хранит примерно 80 000 ключей.
- max_size=1g - максимальный суммарный размер кэша. При превышении Nginx запускает фоновый процесс удаления наименее используемых данных.
- inactive=60m - время неактивности записи. Если файл не запрашивали 60 минут, он удаляется из кэша независимо от max_size.
- use_temp_path=off - запись временного файла сразу в целевую директорию, без промежуточного копирования. Снижает нагрузку на диск.
Разница между max_size и inactive принципиальна: первый ограничивает объём, второй - возраст. Запись может быть удалена по любому из этих условий, что сработает раньше.
Формирование ключа кэша: proxy_cache_key
Ключ кэша определяет, как Nginx сопоставляет запрос с сохранённым ответом. По умолчанию ключ выглядит так:
proxy_cache_key $scheme$proxy_host$request_uri;Проблема дефолтного ключа: он не учитывает метод запроса и может не различать некоторые параметры. Для API с авторизацией по заголовкам это приводит к тому, что ответ одного пользователя отдаётся другому. Рекомендуемая конфигурация:
proxy_cache_key "$scheme$request_method$host$request_uri";Для purge-запросов ключ критичен: вы должны точно воспроизвести его, чтобы удалить нужную запись. Если ключ формируется из переменных, purge-запрос должен использовать те же переменные в том же порядке.
Полная очистка кэша: простой и радикальный метод
Полная очистка удаляет все файлы из директории кэша. Это быстрый способ гарантированно избавиться от устаревших данных, но он имеет серьёзные риски при работающем Nginx.
Безопасная очистка: остановка Nginx и удаление файлов
Если удалить файлы кэша во время работы Nginx, процесс может продолжать держать открытые дескрипторы удалённых файлов. Новые запросы создадут новые файлы, но старые дескрипторы останутся в памяти до перезапуска. В некоторых случаях это приводит к ошибкам 502, когда Nginx пытается прочитать удалённый файл. Безопасная последовательность:
systemctl stop nginx
rm -rf /var/cache/nginx/*
systemctl start nginxПосле запуска проверьте, что кэш пуст и сервер отвечает:
ls -la /var/cache/nginx/
curl -I http://localhost/Первые запросы после очистки пойдут на бэкенд, поэтому возможна временная задержка. Это нормально: кэш заполняется заново.
Очистка без остановки: использование find и других инструментов
Когда остановка сервиса недопустима, можно удалить файлы через find:
find /var/cache/nginx -type f -deleteЭтот метод рискован. Nginx может продолжать использовать удалённые файлы, а новые записи создаются параллельно с удалением. В результате часть кэша остаётся, часть удаляется, и состояние становится непредсказуемым. Используйте этот подход только в крайних случаях, когда простой сервиса обходится дороже, чем возможные ошибки.
Более безопасная альтернатива - автоматизация очистки через cron с предварительной проверкой состояния Nginx.
Выборочная очистка кэша: настройка purge-зоны
Выборочная очистка удаляет только конкретные записи кэша по URL или ключу. Это гибкий подход, который не затрагивает остальные данные и не создаёт всплеск нагрузки на бэкенд.
Установка и настройка модуля ngx_cache_purge
Модуль ngx_cache_purge не входит в стандартную сборку Nginx. В Debian и Ubuntu он доступен в пакете nginx-extras:
apt update
apt install nginx-extrasВ CentOS/RHEL модуль может потребовать компиляции из исходников с параметром --add-module=/path/to/ngx_cache_purge. После установки проверьте, что модуль загружен:
nginx -V 2>&1 | grep -o ngx_cache_purgeЕсли вывод пустой, модуль не установлен, и директива proxy_cache_purge вызовет ошибку конфигурации.
Конфигурация purge-зоны и примеры запросов
Полный пример конфигурации с purge-зоной:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
}
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge my_cache $scheme$request_method$host$1;
}
}Запрос на очистку конкретного URL:
curl -X PURGE http://example.com/purge/api/users/123Обратите внимание: путь в purge-запросе должен соответствовать пути в ключе кэша. Если ключ формируется как $scheme$request_method$host$request_uri, то для URL /api/users/123 purge-запрос должен идти на /purge/api/users/123.
Директивы allow и deny ограничивают доступ к purge-зоне. Без них любой внешний клиент сможет очищать кэш, что создаёт риск DoS-атаки: злоумышленник отправляет множество PURGE-запросов, кэш постоянно пустует, бэкенд перегружается.
Автоматическая инвалидация кэша при обновлении данных
Ручная очистка неудобна при частых обновлениях. Автоматизация встраивает инвалидацию в процесс деплоя или обновления контента, чтобы кэш всегда был актуальным без участия администратора.
Интеграция purge в CI/CD pipeline
Добавьте шаг в pipeline после деплоя приложения. Пример для GitLab CI:
invalidate_cache:
stage: deploy
script:
- curl -X PURGE http://nginx-server/purge/api/users
- curl -X PURGE http://nginx-server/purge/api/products
only:
- mainВажно: purge-зона должна быть доступна из сети CI/CD. Если вы ограничили доступ через allow 127.0.0.1, добавьте IP runner'а или используйте SSH-туннель.
Использование заголовков от бэкенда для инвалидации
Альтернативный способ - управлять кэшем через заголовки ответа бэкенда. Nginx может обходить кэш или не сохранять ответ при определённых условиях:
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_bypass $http_x_cache_purge;
proxy_no_cache $http_x_cache_purge;
}Когда бэкенд возвращает заголовок X-Cache-Purge: 1, Nginx не сохраняет ответ в кэш и не использует кэшированную версию. Это полезно для ответов с ошибками или персонализированных данных. Ограничение: метод не удаляет уже существующие записи, он только предотвращает их создание и использование.
Практические примеры для типовых задач
Кейс 1: API-сервис с кэшированием ответов
Для API, где данные обновляются через POST/PUT/DELETE, настройте кэш только для GET-запросов и добавьте purge-зону:
proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://backend;
proxy_cache api_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
proxy_cache_methods GET HEAD;
}
location ~ /purge-api(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge api_cache $scheme$request_method$host$1;
}
}При обновлении ресурса через POST отправляйте PURGE-запрос на соответствующий GET-URL. Например, после обновления пользователя с ID 123 выполните curl -X PURGE http://api.example.com/purge-api/api/users/123.
Кейс 2: Динамический сайт с кэшированием страниц
Для сайта с авторизацией кэшируйте только публичные страницы, а для авторизованных пользователей обходите кэш:
location / {
proxy_pass http://backend;
proxy_cache site_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 30m;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
}При изменении контента в CMS отправляйте PURGE-запрос на обновлённую страницу. Если CMS поддерживает вебхуки, настройте вызов curl -X PURGE http://example.com/purge/page-url при сохранении записи.
Кейс 3: Балансировка нагрузки с общим кэшем
При балансировке несколько Nginx могут использовать общий кэш на сетевом хранилище:
proxy_cache_path /mnt/shared-cache levels=1:2 keys_zone=shared_cache:10m max_size=10g inactive=120m use_temp_path=off;Очистка выполняется на одном узле, но влияет на все, так как файлы общие. Убедитесь, что purge-запросы отправляются на один выделенный узел, чтобы избежать гонок при одновременной очистке с разных серверов. Для синхронизации можно использовать общий скрипт, который последовательно отправляет PURGE-запросы на каждый узел.
Для кэширования статики и изображений с интеграцией CDN подойдёт отдельное руководство.
Безопасность и предотвращение ошибок 502 при очистке кэша
Ошибка 502 Bad Gateway возникает, когда Nginx не может получить ответ от бэкенда. При очистке кэша это происходит по трём причинам: удаление файлов во время работы Nginx, перегрузка бэкенда после очистки и неправильная конфигурация purge-зоны.
Ограничение доступа к purge-зоне
Purge-зона должна быть доступна только из доверенной сети. Используйте комбинацию allow и deny:
location ~ /purge(/.*) {
allow 10.0.0.0/8;
allow 127.0.0.1;
deny all;
proxy_cache_purge my_cache $scheme$request_method$host$1;
}Для дополнительной защиты добавьте basic-аутентификацию:
location ~ /purge(/.*) {
auth_basic "Purge zone";
auth_basic_user_file /etc/nginx/.htpasswd;
allow 127.0.0.1;
deny all;
proxy_cache_purge my_cache $scheme$request_method$host$1;
}Мониторинг и тестирование после очистки
После очистки проверьте, что Nginx отвечает корректно и кэш заполняется:
curl -I http://example.com/
tail -f /var/log/nginx/error.logДля мониторинга состояния кэша включите stub_status:
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}Запрос curl http://localhost/nginx_status покажет количество обращений к кэшу, попаданий и промахов. После очистки количество промахов временно вырастет - это ожидаемо.
Если вы используете облачную инфраструктуру для размещения Nginx, рассмотрите Timeweb Cloud с готовыми VDS и управляемым Kubernetes для масштабирования кэширующего слоя.
Заключение
Полная очистка через rm -rf проста, но требует остановки Nginx и создаёт всплеск нагрузки на бэкенд. Выборочная очистка через ngx_cache_purge гибче: она удаляет только нужные записи и не затрагивает остальной кэш. Автоматизация через CI/CD или заголовки бэкенда экономит время и снижает риск человеческой ошибки.
Выбирайте метод по задаче: для редких полных сбросов подойдёт ручная очистка, для частых обновлений - purge-зона, для регулярных деплоев - интеграция в pipeline. Тестируйте на staging, ограничивайте доступ к purge-зоне и мониторьте состояние бэкенда после очистки. Полное руководство по безопасной инвалидации кэша в production-среде доступно в отдельной статье.