Настройка CDN, при которой кэш не ломает динамику
Кэширование на CDN ломает динамику не из-за малого TTL, а из-за отсутствия правила: что допустимо отдавать из края, а что обязано доходить до источника. Когда статику, HTML и ответы API обслуживает одна политика, часть страниц замирает в устаревшем виде, а часть промахивается мимо кэша при каждом запросе — и источник получает ту же нагрузку, что и без CDN.
Промахи кэша почти всегда следствие ключа. Если в ключ попадают все параметры строки запроса и заголовки, меняющиеся от пользователя к пользователю, один и тот же файл хранится десятками копий: доля попаданий падает до единиц процентов, а нагрузка на источник растёт кратно. Ключ собирают под смысл ресурса, а лишние параметры вырезают на краю — тогда повторные обращения действительно обслуживаются из кэша.
Статика с хешем в имени файла живёт долго и обновляется без инвалидации: новый файл приходит по новому адресу, а сброс кэша не нужен вовсе. С HTML так нельзя — страницу помечают как условно свежую, с проверкой по ETag, либо дают короткое окно жизни с фоновым обновлением stale-while-revalidate. У API ответы размечают по назначению: публичные справочники живут по общему сроку, персональные помечаются как приватные и не кэшируются на общих узлах.
Отдельная задача — узкое место отдачи. Источник должен обслуживать только то, что не может отдать край, а одновременные запросы на один и тот же промах схлопываются в один поход к бэкенду. Тогда устаревший контент виден предсказуемо и не дольше заданного окна, а нагрузка на источник перестаёт повторять пики трафика.
Разбираем, как это закрывается на практике: какие политики вешаем на группы ресурсов и как проверяем, что кэш не подменяет свежие данные.
Что даёт выстроенный кэш: попадания, скорость, устойчивость
Доля попаданий в кэш и время отклика страницы
Ключ кэша и TTL задаём по типам контента: для статики с хешем в имени файла — длинный, для HTML — короткий с ревалидацией по ETag, для API — отдельный, с учётом заголовка авторизации и Vary. На Cloudflare и аналогах такой набор поднимает долю попаданий в кэш до 85–95% на типовом сайте, и именно она, а не запас мощности источника, определяет время отклика страницы: ответ отдаёт ближайший узел, а не сервер приложения.
Разгрузка источника и поведение под пиком
Каждое попадание — это запрос, который до источника не дошёл. На распродаже или после публикации материала источник получает на порядок меньше обращений, и очередь на нём перестаёт быть узким местом. Директива stale-while-revalidate добавляет устойчивости: посетители получают копию из кэша, пока обновление идёт в фоне и не блокирует выдачу.
Класс отказов, который уходит вместе с настройкой
Правило «медленный или упавший источник не должен ронять страницу» выражается в stale-if-error: при ответе ошибкой клиент получает последнюю валидную копию. Доступность при пике перестаёт зависеть от того, выдержал ли источник нагрузку, — и вместе с настройкой уходит целый класс отказов, который обычно и даёт основную долю простоев.
Варианты кэширования: пограничные узлы, промежуточный слой, гибрид
Выбор между пограничным кэшем, промежуточным слоем и гибридной схемой определяется не «скоростью», а долей динамики в трафике, географией аудитории и тем, насколько болезненна выдача устаревшего ответа. Пограничные узлы вроде сети Cloudflare, собственный кэширующий контур перед приложением и комбинация обоих решают разные задачи — сравниваем по условиям применимости.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Пограничный кэш | Статика и публичные страницы, аудитория разбросана по регионам | Сброс по событию доходит до узлов с задержкой; нет доступа к внутренним данным приложения |
| Промежуточный слой кэша | Много приватных ответов и сложные правила сброса, приложение однородное | Весь трафик идёт через один контур — растёт связность и требования к его отказоустойчивости |
| Гибридная схема | Статика на пограничных узлах, динамика — на промежуточном слое | Сложнее в сопровождении: два набора политик и два места для диагностики |
Раздача статики
Для статики ключ кэша строится по версионированному имени файла, а не по пути. Тогда время жизни можно ставить долгим и помечать ответ неизменяемым: новый релиз приносит новые имена, а старые объекты доживают свой срок без принудительного сброса. Публикация сводится к загрузке файлов в хранилище, и пограничная сеть подхватывает их по первому запросу.
Правила для динамики
Здесь логика обратная: короткое время жизни плюс сброс по событию. HTML отдаётся с малым сроком и фоновым обновлением, чтобы посетитель не ждал пересборки страницы, а персональные ответы либо не кэшируются, либо разделяются по признаку авторизации. Всплески трафика гасит микро-кэш на несколько секунд — он снимает нагрузку с приложения и при этом не превращает данные в устаревшие.
Порядок работ: аудит трафика, правила, проверка, передача
Разбираем не конфигурацию, а факты: как трафик ходит сейчас, что на нём кэшируется и где источник получает нагрузку повторно. Без журналов обращений и текущих заголовков ответа любая правка правил — угадывание. Поэтому ведём работы этапами, где каждый шаг проверяем и обратим.
-
Аудит трафика. Берём журналы обращений за репрезентативный период, считаем долю повторных запросов и попаданий в кэш по группам контента. Отдельно выписываем то, что кэшировать нельзя: авторизованные разделы, ответы с персональными данными, корзину и оформление заказа.
-
Карта маршрутов. Сопоставляем шаблоны адресов, параметры строки запроса и заголовки, которые влияют на ключ кэша. Фиксируем места, где по одному адресу отдаются разные ответы, — это основной источник «залипших» страниц и чужих данных в кэше.
-
Правила кэширования. Задаём раздельные TTL: длинные для статики и медиа, короткие для HTML с обязательной проверкой актуальности, точечные для API — только там, где ответ одинаков для всех. Прописываем заголовки управления кэшем на стороне приложения, а не только в настройках сети доставки.
-
Сброс и выкладка. Настраиваем очистку по путям и меткам, привязываем её к релизу: после публикации новой сборки пользователь получает свежие файлы, а не версию из кэша.
-
Проверка на боевом трафике. Включаем правила на части трафика, сверяем долю попаданий, коды ответов и расхождения с источником. Откат — одной правкой конфигурации, без выкатки приложения.
-
Передача регламентов. Отдаём документацию по правилам, чек-лист для релиза, схему сброса и набор метрик в мониторинг, чтобы команда дальше меняла TTL и маршруты самостоятельно.
Конфигурации, правила инвалидации и схемы на выходе
Настройка заканчивается не отчётом, а комплектом артефактов, с которым команда заказчика работает без нас. Конфигурация лежит в репозитории, доступы разделены, а поведение кэша описано так, что его можно воспроизвести на другой среде и проверить без автора изменений.
- Файлы конфигурации в системе контроля версий: правила кэширования по типам контента, заголовки Cache-Control и Vary, значения s-maxage и stale-while-revalidate, история правок и откат.
- Правила инвалидации: сброс по тегам и префиксам путей после релиза, полный сброс — только как аварийная операция, отдельный порядок для статики, ответов API и HTML.
- Схема прохождения запроса: что отдаётся с ближайшего узла, что уходит к источнику, на каком шаге добавляются заголовки и как считается доля попаданий в кэш.
- Разграничение доступа к панели управления: роли для разработки, поддержки и аналитики, запрет полного сброса без согласования, журнал действий по каждому изменению.
- Инструкции для поддержки: регламент на сброс кэша, проверку свежести после выката и порядок действий при устаревшем ответе — с командами и ожидаемым результатом.
- Карта соответствия типов контента и TTL: какие расширения и маршруты отнесены к каждому профилю — чтобы новый раздел сайта не выпадал из схемы при добавлении.
Кейс: как убрали просадки и снизили нагрузку на источник
До: кэш настраивали «на глаз»
Проект — витрина с каталогом и личным кабинетом: статика, HTML-страницы и API за одним CDN. В кэш попадало около 40% запросов, а TTL стоял одинаковый — час на всё, включая ответы API с персональными данными. В пиковые часы источник получал почти весь поток: время отклика на 95-м проценте доходило до 1,9 с, а после каждой выкладки дежурный вручную сбрасывал кэш по десяткам путей, иногда забывая часть — пользователи видели старую цену и старое наличие.
Что изменили
Развели правила по типам контента. Статику отдаём с длинным TTL и версионированием в имени файла — обновление не требует сброса вовсе. HTML кэшируем коротко, с отдачей устаревшей копии, пока пересборка тянет свежую. Ответы API кэшируются только там, где ключ включает пользователя и параметры запроса, остальное помечено как приватное. Вместо ручных сбросов — метки на контент и один вызов инвалидации на выкладку: Cloudflare сам раскатывает его по узлам.
После
Доля ответов из кэша выросла до 94%, обращения к источнику упали вчетверо, а время отклика под тем же пиком — с 1,9 до 0,3 с. Ручных сбросов стало один-два в неделю вместо двух сотен, и почти все — штатный шаг выкладки. Выдача перестала «дрожать»: просроченная копия отдаётся мгновенно, пока свежая едет с источника, поэтому пользователь не видит ни пустого экрана, ни старой цены после обновления каталога.
Чем отличается кэширование статики от API при настройке CDN?
Статика и ответы API устаревают с разной скоростью: файл сборки с хешем в имени не меняется до следующего релиза, а список заказов теряет актуальность за секунды. Одно правило на весь домен даёт либо устаревшие данные в интерфейсе, либо кэш, который не отдаёт ничего.
| Тип контента | Время жизни записи | Проверка актуальности |
|---|---|---|
| Сборки и изображения с хешем в имени | до следующего релиза | не нужна: имя меняется вместе с файлом |
| HTML и страницы каталога | минуты | условный запрос по ETag, ответ 304 |
| Публичные ответы API | секунды | проверка на актуальность либо отдача старой копии с фоновым обновлением |
| Авторизованные ответы | не кэшируются | обход кэша по заголовку авторизации |
Разделение правил делается не на весь домен, а на уровне путей и типов контента: у статики длинный срок жизни, у API — короткий с обязательной проверкой. Ключ кэша учитывает адрес вместе с параметрами запроса и языком, поэтому выдача по фильтрам и локалям не смешивается, а авторизованные ответы выносятся отдельным правилом.
Проверка актуальности отделяет свежесть от повторной загрузки: узел отдаёт ответ 304, пока содержимое не изменилось, и полный объект — как только изменилось. При коротком времени жизни записи первый запрос после истечения срока уходит к источнику, остальные получают уже готовую копию.
Инвалидация привязана к выпуску: при деплое сбрасываются только затронутые пути или теги, а не кэш целиком. Так длинный срок для статики и короткий для API уживаются в одной схеме без ручных правок.
Сомнения на старте: инвалидация, приватные данные, отладка
Сброс кэша, приватные разделы и проверка того, что кэш реально работает, — три вопроса, которые всплывают ещё на этапе проектирования политики, а не после запуска. Ниже — короткие ответы на них.
Как сбросить кэш, если вышел ошибочный релиз?
Точечная инвалидация по путям и меткам — рабочий инструмент, но она не мгновенная: на узлах кэша копия живёт до истечения своего срока. Поэтому политику строим так, чтобы ошибку можно было снять, не задев остальное: статика и скрипты публикуются с версией в имени файла, а старая версия вытесняется сама по мере обновления ссылок.
Не утекут ли приватные данные в общий кэш?
Приватные разделы, личный кабинет и авторизованные запросы мы не кладём в общий кэш вообще — это правило фиксируется на уровне конфигурации, а не на дисциплине разработчиков. Логика простая: если ответ зависит от того, кто его запросил, узел кэша не имеет права его хранить. Публичным остаётся только то, что одинаково для всех.
Как убедиться, что кэш работает как задумано?
Наблюдаемость кэша — это доля попаданий в разбивке по типам контента: отдельно статика, отдельно страницы, отдельно ответы бэкенда. Если по картинкам и стилям доля попаданий высокая, а по страницам внезапно просела, значит правило сломано или появился новый параметр в адресе. Эти метрики выводим на дашборд вместе с данными сервера-источника — видно, какая доля трафика до него вообще не доходит.
Что делать при инциденте: часть пользователей видит старую версию?
Разбор инцидента начинается со сверки: что отдал узел кэша и что отдал источник на тот же адрес. Дальше смотрим, на каком узле осталась старая копия, снимаем её точечно и правим правило, из-за которого она пережила обновление. Чаще всего причина — забытая метка или слишком длинный срок для адреса, который меняется при каждом релизе.
Обсудим вашу схему кэширования и вернёмся с оценкой
Точная оценка и план работ держатся на понимании того, как устроен ваш трафик и как вы публикуете контент. Ниже — то, что разбираем на первом разговоре: без этих вводных любая политика кэширования получается усреднённой и либо переплачивает за промахи, либо начинает отдавать устаревшие страницы.
Обсудим задачу предметно — по каждому пункту нам достаточно вашей статистики по узлам, доступа к конфигурации и опыта эксплуатации.
- Профиль трафика: доли статики, запросов к API и разметки, суточные пики, соотношение уникальных и повторных обращений — от этого зависит достижимая доля попаданий в кэш.
- Типы контента и допустимое устаревание: каталог, лента, персональные и авторизованные ответы — что можно держать в кэше, а что обязано идти на источник.
- Ограничения источника: запас по пропускной способности, лимиты на число обращений и поведение при массовом промахе кэша после сброса.
- Требования к сбросу кэша: как быстро правка должна становиться видимой, есть ли версионирование путей или групповые метки для инвалидации.
- Схема публикации: как релиз доезжает до узлов и как это согласуется с инвалидацией, чтобы не отдавать смешанные версии.
- Доступы и права: где хранится конфигурация, кто меняет правила и как фиксируются изменения TTL.
- Режим поддержки: нужен ли мониторинг доли попаданий, оповещения о росте трафика на источник и регламент правок политики.
Опишите задачу — вернёмся с оценкой и планом работ: раскладка TTL по типам контента, порядок инвалидации и состав мониторинга.







