GH GambleHub

CDN-кеширование и TTL-оптимизация

Краткое резюме

CDN-кеш — это «ускоритель + щит» между пользователем и origin. Он работает хорошо, когда:

1. Ключ кэша (cache key) стабилен и не содержит «шума».

2. TTL-политика под нагрузку: `s-maxage`/`max-age` + `stale-while-revalidate/if-error`.

3. Инвалидация управляется: по тегам/префиксам + «мягкие» purge.

4. Включены tiered-cache/origin-shield и negative-cache.

5. Есть наблюдаемость: hit-ratio по слоям, p95 TTFB, доля возвратов 304.

Базовые хедеры и что они значат

`Cache-Control`:
  • `max-age=` — TTL для браузера.
  • `s-maxage=` — TTL для CDN/прокси (перекрывает `max-age`).
  • `stale-while-revalidate=` — отдаем устаревшее, параллельно обновляем.
  • `stale-if-error=` — отдаем устаревшее при ошибке origin.
  • `immutable` — ресурс не меняется (подходит для версиированных ассетов).
  • `ETag` / `Last-Modified` — условия для 304, экономят байты/CPU origin.
  • `Vary` — список заголовков, влияющих на ключ кэша (использовать сдержанно!).
  • `Surrogate-Control` — «расширенный» Cache-Control для CDN (если поддерживается).
  • `Expires` — устаревший, но все еще учитывается клиентами.
Пример (статика, год):

Cache-Control: public, max-age=31536000, immutable
Пример (полу-динамика с безопасным устареванием):

Cache-Control: public, s-maxage=300, max-age=60, stale-while-revalidate=600, stale-if-error=86400
ETag: "a1c3..."

Ключ кэша: дизайн и нормализация

Цель — чтобы одинаковые по сути запросы попадали в один и тот же объект.

Нормализация URL: регистр, двойные слэши, трейлинг-слэш, порядок query-параметров.
Игнор «шума»: `utm_`, `fbclid`, `gclid`, произвольные реф-теги.
Ограниченный Vary: только реально значимые заголовки (`Accept-Encoding`, иногда `Accept`, `Accept-Language` для локали).
Device-class: если нужно, используйте 2–3 класса (mobile/desktop/tablet), а не бесконечные user-agent ветки.
Auth-контекст: по умолчанию не кешируйте приватное; используйте signed-URLs/cookies-bypass или разделение публичных/приватных путей.

Fastly-стиль (псевдо):

Surrogate-Key: product:123 catalog
Cache-Control: public, s-maxage=300, stale-while-revalidate=600
Vary: Accept-Encoding

TTL-стратегии по типам контента

ТипTTL CDN (`s-maxage`)Браузер (`max-age`)Дополнительно
Версиированные ассеты (`/app.a1b2.js`)1 год1 год`immutable`; инвалидация не нужна
Каталоги/лендинги1–10 мин30–120 с`stale-while-revalidate=10–30 мин`
Изображения (ресайзы)10–60 мин5–15 минVary по `Accept` (webp/avif)
API GET (кэшируемые)10–120 с0–30 сТолько идемпотентные; `stale-if-error` 5–60 мин
Ошибки 500/timeout00Negative-cache 30–120 с (на уровне CDN), не кэшировать 401/403/POST

Политики инвалидации

By URL/Prefix: «смести все под `/static/2025-11-05/`».
By Tag/Key: «снять весь `catalog` и `product:123`».
Soft purge: пометить как устаревшее, не стирать объект — быстрее повторное наполнение.
Event-driven: CI/CD или админ-событие вызывает webhook «invalidate tags».

Рекомендация: объединяйте обе тактики: версионирование путей для ассетов + tag-purge для контента/страниц.

Tiered-cache, origin-shield и prewarm

Tiered-cache: региональные слои CDN → меньше запросов к origin.
Origin-shield: один «щитовой» POP к origin — улучшает локальность и hit-ratio.
Prewarm (pre-fetch): прогрев горячих URL/кэшей перед ивентом/релизом.
Negative-cache: кратковременно кешируйте 5xx/Timeout (30–120 с), чтобы не завалить origin штормом ретраев.

Кеш API: когда можно

Только GET/HEAD и идемпотентные.
Ключ: путь + существенные query (например, `?category=...&page=...`).
Валидация: `ETag`/`Last-Modified` и короткий `s-maxage`.
Фильтры по пользователю: вынесите персонализацию на клиент/edge-функцию или используйте signed-requests + «публичный» ответ.

Пример (API, 30 с + SWR):

Cache-Control: public, s-maxage=30, max-age=5, stale-while-revalidate=120, stale-if-error=600
ETag: "feed-v42"

Защита от отравления кэша (cache poisoning)

Жесткая нормализация URL/заголовков; белый список параметров в ключе.
Обрезка подозрительных заголовков/дубликатов (`X-Forwarded-`, расширенные `Accept`).
Ограничение `Vary` и контроль размера/кол-ва заголовков.
Разделение доменов: приватное/админ — на отдельном имени без кэша.
Валидация ответов: не кэшируйте 4xx (кроме 404 для статик), не кэшируйте «пользовательские» страницы без явной политики.

Сжатие и форматы

Brotli для текстовых (js/css/json), gzip — fallback; пред-сжатые ассеты допустимы.
Images: webp/avif там, где поддержка; используйте `Vary: Accept` + производные деривативы.
Range-requests для видео/аудио: CDN кэширует чанки.
Content-Negotiation: держите низкий кардиналитет ключа (device-class вместо сырых UA).

Наблюдаемость и SLO

Ключевые метрики

Hit-ratio (by bytes/requests) на edge/tier/shield.
p50/95/99 TTFB по регионам и типам (статик/API).
Fill-rate/Origin egress — сколько уходит к origin.
304 rate и средний размер ответа.
Error budget: доля `stale-if-error`/`SWR` выдач; частота purge.

Примеры SLO

`p95 TTFB` статики регионально ≤ 120–150 мс, API GET кешируемых ≤ 200–250 мс.
Edge hit-ratio статики ≥ 90%, полу-динамики ≥ 60%.
Доля ответов из stale-ветки при ошибках ≤ 0.5% за 30 дней.

Конфиг-шпаргалки

Nginx (reverse-proxy перед CDN или в self-PoP)

nginx proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CDN:512m max_size=100g inactive=7d;

map $args $clean_args {
"~(^    &)(utm_    gclid    fbclid) """; # default $ args simplified example;
}

server {
listen 443 ssl http2;
set $cache_key "$scheme$request_method$host$uri?$clean_args    $http_accept    $http_accept_encoding";
location /static/ {
proxy_cache CDN;
proxy_cache_key $cache_key;
proxy_ignore_headers Set-Cookie;
add_header Cache-Control "public, s-maxage=86400, max-age=3600, stale-while-revalidate=600" always;
proxy_pass https://origin_static;
}

location /api/public/ {
proxy_cache CDN;
proxy_cache_key $cache_key;
proxy_cache_valid 200 30s;
add_header Cache-Control "public, s-maxage=30, max-age=5, stale-while-revalidate=120, stale-if-error=600" always;
proxy_set_header If-None-Match $upstream_http_etag;
proxy_pass https://origin_api;
}
}

Envoy (SWR + negative-cache, концепт)

yaml http_filters:
- name: envoy. filters. http. cache typed_config:
"@type": type. googleapis. com/envoy. extensions. filters. http. cache. v3. CacheConfig typed_config:
"@type": type. googleapis. com/envoy. extensions. cache. simple_http_cache. v3. SimpleHttpCacheConfig
Cache-Control/Surrogate-Control Header Cache Policies
We cache 5xx errors briefly via route/retry policy + local_rate_limit

Хедеры для «быстрых» ассетов


Cache-Control: public, max-age=31536000, immutable
ETag: "hash"
Content-Encoding: br

Хедеры для полу-динамики (каталоги)


Cache-Control: public, s-maxage=600, max-age=120, stale-while-revalidate=1800, stale-if-error=86400
Vary: Accept-Encoding, Accept

FinOps: как кэш экономит деньги

Egress origin ↓, меньше CPU/DB-нагрузки → ниже инфраструктурные расходы.
Меньше запросов до платных бэкендов (search/index/images).
Целевая метрика: $/снижение p95 и $/снижение egress на 1 ГБ — отслеживайте послезапусковой эффект.

Специфика для iGaming/финтех

Каталоги провайдеров/ассеты: версионированные пути + годичный TTL.
Лендинги событий/турниров: 1–5 мин `s-maxage` + `SWR` на 10–30 мин; tag-purge при обновлении.
Лив-страницы (коэффициенты/таблицы): частичный кэш JSON-блоков, короткие TTL (5–30 с), для персональных блоков — клиентский рендер.
PSP/платежные эндпоинты: не кешируем, строгое `no-store`; кэшируйте только справочники (BIN-таблицы, статусы).
Антибот: кэширование статик/GET, «серые» маршруты для подозрительных ASN; не допускайте `Vary` по шумным заголовкам.

Чек-лист внедрения

  • Описан ключ кэша: нормализация URL, список допускаемых query, `Vary` только по нужному.
  • Разделены публичные/приватные пути; приватное — `no-store` и bypass CDN.
  • Введены TTL-лестницы по типам контента; настроен `SWR/if-error`.
  • Настроены tiered-cache + origin-shield; включен negative-cache 5xx (короткий).
  • Есть tag/URL purge, soft purge; интеграция с CI/CD.
  • Включена компрессия (br/gzip), веб-форматы изображений и range-ответы.
  • Метрики: hit-ratio by layer, p95 TTFB, 304 rate, origin egress; алерты на провалы.
  • Плейбуки: прогрев кэша перед пиками, экстренный purge, деградация origin.

Типичные ошибки

Без-версио ассеты с большим TTL → «залипшие» бандлы у пользователей.
Чрезмерный `Vary` (по `User-Agent`, всем заголовкам) → взрыв кардинальности и низкий hit-ratio.
Кэширование 4xx/401/403/приватного контента.
Отсутствие negative-cache → лавина запросов на деградный origin.
Нет tag-purge → массовые точечные purge и «шторм» re-fill.
Ключ кэша включает «шумные» UTM/реф-параметры.
Слишком короткий TTL для статики → лишняя нагрузка на CDN и origin.

Мини-плейбуки

1) Прогрев кэша перед событием

1. Сбор топ-N URL по логам → 2) Параллельный prefetch (rate-limited) по регионам → 3) Проверка hit-ratio ↑ и p95 ↓.

2) Экстренный soft-purge катологов

1. Отправить `PURGE`/tag-clear → 2) CDN отдает stale и фоном подтягивает свежие → 3) Проверить отсутствие шипов на origin.

3) Отказ origin

1. `stale-if-error` выручает X часов → 2) Включить баннер «техработы» на edge → 3) По восстановлении — целевой warm-up.

Итог

Сильная CDN-стратегия = правильный ключ кэша + осмысленные TTL с SWR/if-error + управляемая инвалидация + tiered/shield + наблюдаемость. Зафиксируйте политику в хедерах и IaC, измеряйте hit-ratio и p95, планируйте прогрев под пики — и пользователи всегда получат быстрый ответ, а origin останется жив даже в самый горячий час.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Telegram
@Gamble_GC
Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.