Типичная сцена: 1000 RPS и бэкенд захлёбывается
Нагруженное приложение (1000 RPS) легко упирается в лимиты базы данных или утилизацию CPU из-за повторяющихся вычислений. Бэкенд на Node.js или Python с трудом обрабатывает каждый запрос, особенно если есть повторяющиеся SQL-запросы или тяжелые шаблоны. Время ответа может достигать 500ms, а P99 — зашкаливать. Правильно настроенный reverse proxy с кэшированием решает несколько задач: SSL termination, статическая раздача, кэширование ответов и балансировка. Мы часто видим проекты, где бэкенд отдаёт каждый запрос напрямую, а nginx стоит только как SSL-терминатор — это прямой путь к перегрузке.
Наши инженеры за 10+ лет настроили сотни таких схем. Результат: время ответа падает на 70% для кэшируемых запросов, нагрузка на бэкенд снижается в разы. Сравнение: кэш nginx раздаётся в 10 раз быстрее, чем кэш Redis/Memcached на бэкенде (микросекунды против миллисекунд). Стоимость такого решения — от нескольких часов работы, а экономия ресурсов сервера может достигать тысяч долларов в месяц. Например, после внедрения кэша можно сократить количество серверов с 5 до 2, экономя $3000 ежемесячно.
Базовая конфигурация reverse proxy
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/ssl/certs/example.com.fullchain.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
}keepalive 32 и proxy_http_version 1.1 с Connection "" — обязательная пара для persistent connections. Без неё каждый запрос открывает новое TCP-соединение, что на нагруженном сервере выливается в тысячи TIME_WAIT. TLS handshake занимает около 2ms, а отдача из кэша — менее 0.1ms, поэтому persistent connections критичны.
Кэширование ответов бэкенда
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=backend_cache:10m max_size=100m inactive=60m use_temp_path=off;
server {
location /api/ {
proxy_cache backend_cache;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://backend;
}
}
}proxy_cache_use_stale — один из важнейших параметров. При ошибке бэкенда nginx отдаёт устаревший кэш вместо 502. updating защищает от Thundering Herd: пока один запрос обновляет кэш, остальные получают старое значение. Согласно официальной документации nginx (https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_use_stale), это ключевое средство для высоконагруженных систем. Добавьте заголовок X-Cache-Status — увидите HIT, MISS, STALE или EXPIRED.
Как проверить работу кэша?
Добавьте заголовок add_header X-Cache-Status $upstream_cache_status; и смотрите в ответе HIT, MISS, STALE и т.д. Также наблюдайте за падением времени ответа и нагрузки на бэкенд. P99 latency должен снизиться с 500ms до 50ms. Для мониторинга используйте Prometheus метрики из nginx stub_status.
Какие заголовки влияют на кэширование?
Бэкенд управляет кэшем через HTTP-заголовки. Если бэкенд вернул Cache-Control: no-cache, nginx не кэширует ответ. Для принудительной инвалидации используйте purge API:
location ~ /purge(/.*) { allow 127.0.0.1; deny all; proxy_cache_purge backend_cache "$scheme$host$1"; } Используйте curl: curl -X PURGE http://localhost/purge/api/products/123.
Кэширование статики и раздача напрямую
Статические файлы (jpg, css, js и т.д.) можно кэшировать либо отдавать напрямую из nginx, минуя бэкенд. Прямая отдача снижает нагрузку на CPU бэкенда на 30–50%. Пример для статики с хешем:
location /static/ {
alias /var/www/app/public/static/;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
gzip_static on;
}immutable говорит браузеру: файл никогда не изменится, не делай условный запрос.
Почему стоит использовать nginx для кэширования, а не кэш на бэкенде?
| Критерий | Кэш на nginx | Кэш на бэкенде (Redis/Memcached) |
|---|---|---|
| Время отдачи | Микросекунды (из памяти ядра) | Миллисекунды (сеть + сериализация) |
| Нагрузка на бэкенд | Ответ не доходит до приложения | Приложение всё равно обрабатывает запрос |
| Холодный старт | Файловый кэш сохраняется после перезапуска | Прогрев кэша после перезапуска |
| Сложность настройки | Конфиг nginx + purge API | Отдельный сервер, клиенты, инвалидация |
Процесс работы
- Аудит: анализ конфигурации, логов, метрик через
stub_statusили Prometheus. Определяем узкие места: где кэш принесёт наибольший эффект. - Проектирование: выбор размера кэша, зон, правил инвалидации. Рассчитываем keys_zone и max_size исходя из среднего размера ответа (например, 10M зона хранит около 80 000 ключей).
- Реализация: развёртывание reverse proxy с кэшированием, балансировкой, SSL. Используем Ansible или Terraform для repeatable деплоя.
- Тюнинг: подбор таймаутов, буферов, keepalive под характеристики бэкенда. Например, для бэкенда с долгими ответами увеличиваем proxy_read_timeout до 120s.
- Тестирование: нагрузочное тестирование с помощью wrk или k6. Цель — P99 latency < 100ms для кэшируемых запросов.
| Масштаб | Срок |
|---|---|
| Базовый reverse proxy | 1 день |
| + кэширование с purge API | 2–3 дня |
| + балансировка нескольких upstream | 3–5 дней |
Стоимость рассчитывается индивидуально после аудита инфраструктуры и нагрузочных паттернов. Свяжитесь с нами — подготовим предложение с учётом ваших задач.
Что входит в работу
- Полная документация конфигурации и инструкция по эксплуатации.
- Доступ к репозиторию с Ansible-ролями или Terraform-модулями.
- Обучение команды (2 часа): как сбрасывать кэш, читать логи, тюнить параметры.
- Гарантия на настройку — 30 дней.
Типичная проблема: кэширование аутентифицированных запросов
По умолчанию nginx кэширует ответы без учёта заголовка Authorization. Один пользователь может получить ответ, предназначенный другому. Решение: добавить proxy_cache_bypass $http_authorization; или включить Authorization в cache key: proxy_cache_key "$scheme$host$request_uri$http_authorization";. Проверьте, что это не нарушает безопасность.
Как правильно тюнить proxy_cache_use_stale?
proxy_cache_use_stale определяет, когда отдавать кэш при проблемах с бэкендом. Значение updating — ключевое для высоконагруженных систем. Оно защищает от эффекта Thundering Herd: nginx разрешает одному запросу обновить кэш, а остальные получают старое значение, не нагружая бэкенд. Рекомендуем всегда использовать updating в комбинации с error timeout.
Закажите профессиональную настройку — наши инженеры с 10+ летним опытом помогут развернуть production-ready reverse proxy для вашего проекта. Получите консультацию уже сегодня: мы проанализируем вашу инфраструктуру и предложим оптимальную конфигурацию.







