# Кэширование Nginx и Cloudflare: где каждый уровень окупается

> Изучите кэширование Nginx и Cloudflare при ограниченном бюджете: что кешировать на краю, в Nginx или в приложении, и где дублирование правил только мешает.

## Почему это быстро становится запутанным

Один запрос может пройти через несколько кэшей прежде чем приложение начнёт что‑то делать. Cloudflare может ответить на краю, Nginx может хранить собственную копию, а в приложении могут кэшироваться данные или готовые ответы. Быстрые страницы — это хорошо. Устаревшие — нет. Как только появляется старый контент, команды часто теряют время, пытаясь угадать, какой слой его отдал.

Каждый слой видит запрос по‑своему. Cloudflare заботится об ответе на краю, Nginx — о том, что вернул origin. Приложение обычно кэширует что‑то более специфичное: результат запроса, сгенерённый фрагмент или персонализированный ответ. Если один слой отдаёт старую версию, следующий слой никогда не увидит свежую.

Типичный путь запроса выглядит так:

- Cloudflare проверяет, есть ли у него страница или ресурс.
- Nginx проверяет свой кеш или пересылает запрос дальше.
- Приложение смотрит в память, Redis или базу данных.

Эта стек‑комбинация встречается часто при ограниченном бюджете, потому что каждая часть кажется дешёвой и полезной сама по себе. Проблема начинается, когда команды добавляют кэширование поэтапно без явного плана. Страница кажется медленной — кто‑то добавляет ещё один кэш — и скоро никто не может сказать, какое правило что исправило.

Заголовки часто осложняют ситуацию. Приложение может отправлять один `Cache-Control`, Nginx — переписывать его, а Cloudflare следовать своим настройкам. Затем вы очищаете один слой и всё ещё видите старую страницу. Через несколько обновлений, приватное окно и проверку заголовков вы уже потратили полчаса на проблему, вызванную пересекающимися правилами.

Дублирование кэширования имеет реальную стоимость. Чем больше слоёв — тем больше очисток, исключений и способов случайно закешировать не то. Для маленького SaaS время на отладку устаревших страниц может стоить дороже, чем чуть более нагруженный origin.

Кэширование работает лучше, когда у каждого слоя одна ясная задача. Как только два слоя пытаются решать одну и ту же задачу, выигрыш в скорости сглаживается, а отладка замедляется.

## Что лучше всего делает каждый слой

Каждый уровень кэша решает разный тип задержки. Когда команды смешивают их, они часто кешируют одно и то же три раза и всё равно получают медленные страницы или устаревший контент.

Cloudflare эффективен на краю. Он хорош для файлов, которые многие посетители запрашивают снова и снова: изображения, скрипты, стили и шрифты. Он также может кешировать некоторые полные страницы, когда контент почти не меняется. Так как он ближе к посетителю, он сокращает время передачи и поглощает всплески трафика до того, как они доберутся до вашего сервера.

Nginx лучше работает на origin. Он сидит перед приложением и управляет HTTP‑поведением: заголовки, сжатие, маршрутизация и правила кэширования. Он может кешировать краткоживущие ответы приложения, что полезно для публичных страниц и API‑эндпоинтов, которые многие пользователи запрашивают в одинаковом виде. Он также сообщает Cloudflare, что безопасно кешировать, через понятные заголовки.

Кэш в приложении решает другую задачу. Он хранит работу, которую понимает только приложение: медленный запрос к базе, вычисляемый отчёт, проверку прав или часть дашборда. Это экономит время базы и CPU. Если контент меняется в зависимости от пользователя, аккаунта или плана, приложение обычно узнаёт об этом первым — Cloudflare и Nginx нет.

Полезно думать в терминах расстояния и знаний. Cloudflare далёк от вашего кода, но близок к посетителю. Nginx близок к приложению и хорош в HTTP‑правилах. Приложение знает данные лучше всех.

Такое разделение обычно держит расходы в узде. Пусть Cloudflare обслуживает повторный статический трафик, Nginx кеширует безопасные ответы origin на короткое время, а приложение поддерживает дорогие данные «тёплыми». Когда у каждого слоя своя задача, система быстрее и проще в отладке.

## Начните с пути запроса

Хороший план кэширования начинается с простой карты того, что люди запрашивают. Если пропустить этот шаг, вы будете кешировать то, что кажется медленным, а не то, что реально стоит денег.

Запишите основные типы страниц и API‑маршруты. Будьте конкретны: маркетинговые страницы, документация, pricing, скриншоты продукта, HTML дашборда, результаты поиска, login, настройки аккаунта, экспорт, фоновые API‑вызовы.

Простое разделение достаточно:

- публичные страницы, доступные всем
- статические файлы: изображения, JS, CSS
- публичные API‑ответы, используемые многими посетителями
- пользовательские страницы за логином
- приватные API‑маршруты с персональными данными

Затем отметьте, как часто меняется каждый из них. Некоторые материалы обновляются раз в месяц. Некоторые — каждый час. Некоторые значения, как запас товара, метрики в реальном времени или счётчики непрочитанных сообщений, могут меняться каждые несколько секунд. Это определяет, где кэш безопасен, а где он только создаст устаревание.

Сделайте жёсткое разделение между публичным и приватным контентом. Пост в блоге, справочная страница или скриншот продукта обычно могут жить на краю некоторое время. Страница биллинга, админка или всё, что содержит имя пользователя, баланс или индивидуальные права, требует осторожности. Если ответ зависит от cookies, заголовков авторизации или настроек арендатора, считайте его приватным, пока не докажете обратное.

Потом посмотрите, что действительно жрёт CPU. Команды часто ошибаются в догадках. Страница может выглядеть тяжёлой, но дорогостоящая часть может быть в API‑маршруте, который объединяет несколько таблиц, рендерит график или выполняет проверки прав на каждый запрос. Именно там кэширование экономит реальные деньги.

Типичная схема для малого SaaS часто такая: домашняя страница, документация и активы хорошо на краю; Nginx помогает с сжатием, статикой и несколькими краткоживущими публичными ответами; приложение хранит самый контекстозависимый кеш, например дорогие результаты запросов или виджеты дашборда. Такое разделение обычно лучше, чем повторять одни и те же правила в каждом слое.

Если вы можете ответить на четыре вопроса для каждого запроса — кто его видит, как часто он меняется, публичен ли он и сколько стоит его генерация — остальное планирование становится гораздо проще.

## Как размещать кэши шаг за шагом

Начните с края, а не изнутри приложения. В большинстве случаев самый дешёвый выигрыш приходит от того, что Cloudflare кеширует статические файлы сперва: CSS, JavaScript, шрифты, изображения и другие версионированные активы. Эти файлы редко требуют обращения к origin, поэтому каждый hit на краю экономит полосу, CPU и время.

Затем посмотрите на нагрузку на origin. Если сервер всё ещё тратит много времени на рендеринг одних и тех же публичных страниц, добавьте короткий Nginx‑кеш только для публичного HTML. Хорошие кандидаты: домашняя страница, pricing, документация или пост в блоге. Держите кеш коротким, обычно 30–120 секунд, чтобы обновления всё ещё быстро показывались.

Простой порядок подходит большинству команд:

1. Пусть Cloudflare кеширует статические активы с долгими TTL и версионированными именами файлов.
2. Держите страницы входа, ответы авторизации, дашборды и пользовательские API вне edge‑кеша.
3. Добавляйте Nginx‑кеш для публичного HTML только если origin всё ещё горячий.
4. Кешируйте дорогие чтения из базы в приложении с понятными TTL.
5. Измеряйте hit rate, время ответа и нагрузку на сервер после каждого изменения.

Третий шаг — где многие команды ошибаются. Они включают Nginx‑кеш до того, как проверили, не забрал ли уже Cloudflare большую часть простого трафика. Если Cloudflare справляется с активами, вам может не понадобиться много Nginx‑кешей.

Внутри приложения фокусируйтесь на медленных чтениях, которые повторяются. Это может быть таблица цен, feature flags, список планов или тяжёлый отчётный запрос, который многие пользователи запускают. Давайте каждому кешированному результату явный срок жизни: 15 секунд, 1 минута или 5 минут. Подбирайте значение по тому, как часто данные реально меняются.

Простой пример для SaaS проясняет картину. Пусть Cloudflare отдаёт активы лендинга. Пусть Nginx держит публичные маркетинговые страницы 60 секунд при всплесках трафика. Дашборд и всё за логином — вне edge. А внутри приложения кешируйте дорогой запрос к базе, собирающий суммарные данные, на короткое время.

После каждого шага проверяйте изменения. Если hit rate вырос и нагрузка упала — оставьте. Если ничего не поменялось — уберите лишний слой и держите конфигурацию простой.

## Простой пример для SaaS

Представьте маленький SaaS для командного планирования. Есть публичная домашняя страница, документация, страница цен, дашборд и API. Самое дешёвое решение часто работает лучше, когда у каждого кэша своя задача.

Публичные маркетинговые страницы можно держать за Cloudflare с долгим кешем. Домашняя страница, посты в блоге, страницы фич и документация обычно не меняются в течение дня, поэтому TTL в несколько часов или даже дольше часто подходит. Cloudflare обслуживает повторные визиты рядом с пользователем, снижает трафик к origin и помогает маленькому серверу пережить запуск или рекламный пик.

Страница цен требует иного правила. Команды меняют планы, тексты пробных периодов и заметки о скидках чаще, чем думают. Эту страницу всё ещё можно кешировать на краю, но с коротким TTL и простыми правилами очистки. Десять минут часто хватает. Если команда меняет цену и хочет увидеть её сразу, очищайте только эту страницу, а не всё подряд.

Для залогиненных пользователей избегайте edge‑кеша. Дашборд, биллинг и API аккаунта должны проходить через Cloudflare без сохранения персонализированных ответов. Внутри приложения кешируйте дорогие данные: лимиты плана, права команды, feature flags и отчёты, которые собираются сотни миллисекунд. Пользователи получают быстрый отклик, а приложение не рискует показать данные одного клиента другому.

Nginx уместен там, где контент публичен, но всё ещё стоит CPU. Частый пример — ресайз изображений. Другой — публичная лента, которую многие запрашивают, хотя она обновляется каждые несколько минут. Nginx может держать такие ответы, чтобы приложение не повторяло одинаковую работу.

Чистая карта маршрутов может выглядеть так:

- Главная, блог и документация: долгий кеш в Cloudflare
- Страница цен: короткий кеш в Cloudflare
- Дашборд и пользовательский API: без edge‑кеша, только кеш в приложении
- Трансформации изображений и публичные фиды: кеш Nginx на origin

Именно так настройка окупается. Если вы кешируете один и тот же полный ответ в Cloudflare, Nginx и приложении, вы обычно получаете ещё один устаревший слой для отладки. Пусть Cloudflare поглощает публичный трафик, Nginx решает повторяющуюся работу origin, а приложение кеширует то, что дорого пересчитывать.

## Где дублирование кэша отнимает время

На бумаге дублирование кэширования выглядит безопасно. На практике оно чаще добавляет работы, чем даёт скорость.

Частый пример — публичная страница, кешируемая и Cloudflare, и Nginx. Если страница маленькая, почти статична и уже недорога в отдаче, второй кеш может сэкономить лишь несколько миллисекунд. Зато он однозначно добавляет ещё одно место, где всё может устареть.

Та же проблема внутри приложения. Команды иногда кешируют результаты базы в Redis или памяти, хотя Nginx уже отдал итоговый ответ быстро, и страница почти не меняется. Этот дополнительный кэш усложняет код, правила инвалидации и добавляет ещё одну точку, куда смотреть, когда пользователи жалуются на старый контент.

При ограниченном бюджете каждый кэш должен «платить за аренду». Если один слой уже справляется с задачей, добавление ещё одного ради того же контента — часто просто лишняя работа.

### Когда пересечение становится проблемой

Боль обычно начинается с рассинхронизации TTL. Cloudflare может хранить страницу час, Nginx — 10 минут, а кэш в приложении — 24 часа. Кто‑то обновляет цену в полдень, очищает один кэш и думает, что всё в живую. Затем служба поддержки получает три скриншота от трёх пользователей: один видит новую цену, другой — старую страницу из Cloudflare, третий получает свежий HTML с устаревшими данными из кэша приложения. Никто не понимает, какой слой «выиграл», потому что у всех разные сроки жизни.

Именно поэтому дублирование кэша тратит время в первую очередь на отладку, а не только на настройку.

Короткая проверка полезна:

- Если Cloudflare уже хорошо кеширует публичную страницу, спросите, нужен ли Nginx тот же полный ответ.
- Если Nginx отдает ответ за миллисекунды, спросите, нужен ли приложению собственный кеш для того же вывода.
- Если вы не можете объяснить порядок очистки в одном предложении, скорее всего у вас слишком много кэшей.

Обновления усугубляют ситуацию. Одно изменение может означать очистку Cloudflare, удаление файлов Nginx cache, удаление ключей в Redis и иногда прогрев страниц заново. Работа множится, а пользователей интересует лишь корректность страницы.

Проще настроенная система обычно лучше: пусть Cloudflare отвечает за публичное кеширование на краю, Nginx — за обратное проксирование и, возможно, несколько дорогих ответов, а приложение — только за данные, которые действительно дорого пересчитывать.

## Ошибки, которые создают устаревший или неверный контент

Самый быстрый способ сломать сайт — закешировать то, что меняется от пользователя к пользователю. Дашборд, корзина, страница аккаунта или страница цен с персональными скидками никогда не должны лежать в публичном кеше только потому, что в одном тесте всё выглядело нормально.

Cookies и заголовки авторизации — обычная ловушка. Если ответ зависит от cookie входа, сессионного токена или заголовка `Authorization`, считайте его приватным, если у вас нет очень явного правила, которое сначала удаляет личные данные. Одна неправильная запись в Cloudflare или Nginx может показать Алисе страницу, предназначенную для Боба.

Ключи кэша создают более тихие ошибки. Страница может казаться корректной для большинства, но быть неправильной для пользователей на мобильных, на другом языке или с фильтром в URL. Если приложение отдаёт разный вывод по локали, устройству или параметрам запроса, ключ кэша должен включать эти различия.

Типичные промахи выглядят так:

- Английская и французская страницы разделяют один кэш.
- Мобильный и десктопный макеты хранятся в одном ответе.
- Параметры `?page=2` или `?sort=price` игнорируются.
- Тестовый пользователь и платный пользователь попадают на один и тот же HTML.

Долгие TTL усугубляют всё это. Команды часто ставят час или день сначала и обещают починить инвалидацию позже. Порядок неправильный. Тестируйте процесс очистки и прогрева перед увеличением TTL. Начните с короткого срока жизни, подтвердите, что обновления появляются вовремя, и только потом растягивайте TTL там, где правила выдерживают нагрузку.

Ещё одна ошибка — винить всё медленные маршруты в отсутствии кэша. Некоторые маршруты медленны из‑за плохого запроса, чрезмерной работы приложения или нескольких внешних вызовов перед рендером. Кэш может скрыть проблему на время, но не исправит логику. Если инвалидация сложна или контент меняется каждую секунду, вероятно сам маршрут нужно оптимизировать.

Это особенно важно при попытке держать инфраструктуру компактной. Каждый лишний слой усложняет отладку. Когда контент кажется устаревшим, теперь нужно спрашивать, какой слой его держал, какое правило сработало и послал ли приложение неверные заголовки. Публичное кеширование стоит резервировать для контента, который действительно общий, предсказуем и легко обновляем.
