Инвалидация кэша в стриминге: редко используют, часто неправильно

Автор: Николай СапуновОбновлено: август 202619 мин чтения
Содержание статьи +

TL;DR

Инвалидация кэша – это команда CDN забыть копию объекта, которую он хранит, чтобы следующий запрос пошёл за свежей версией к origin. В стриминге это неверный инструмент почти для всего, ради чего к нему тянутся неопытные команды: деплоев, изменений плейлиста, обновлений лестницы, починок багов. Эта работа закрывается тремя другими паттернами – коротким Cache-Control на манифестах, длинным Cache-Control плюс версионированными именами файлов на сегментах и переписыванием segment timeline в самом манифесте. Инвалидация остаётся для того, что эти паттерны не закрывают: ротация ключей DRM, takedown по DMCA или GDPR, редакционное снятие или развёрнутый баг в куске контента, который не может ждать трёх часов на TTL.

Зачем это нужно

Если у вас стриминговый продукт на CDN, рано или поздно кто-нибудь в команде предложит «давайте просто очистим кэш» как фикс проблемы. Симптом они опишут правильно – пользователи видят старый контент. Инструмент почти всегда будет выбран неправильно. Массовая инвалидация в большинстве CDN медленная, платная сверх небольшого фритира и тихо разрушает cache hit ratio, на котором держится ваш бюджет. Эта статья – для инженера, которому дали кнопку purge, тимлида, желающего понять, когда это реально правильный ответ, и продакта, которому нужен короткий чек-лист до того, как прилетит очередной «срочный takedown».

Что такое «инвалидация кэша» на самом деле

CDN хранит копии ваших файлов на edge – рядом со зрителем – чтобы отвечать на запросы, не идя к origin. Инвалидация – это команда CDN: забудь свою копию этого файла; следующий, кто его попросит, получит свежий байт из origin. Большинство CDN (Cloudflare, Fastly, Akamai, Google Cloud CDN) называют операцию purge; Amazon CloudFront предпочитает термин invalidation. Под капотом – одно и то же.

Три детали внутри этого простого определения регулярно бьют команды.

Во-первых, инвалидация не моментальна. CloudFront документирует 5–25 секунд для своих новых cache tag инвалидаций (P95) и 10–15 минут для классических path-инвалидаций – это время распространения по всем edge. Fastly известен скоростью: его purge-all завершается глобально за ~150 миллисекунд. Но для лайв-сегментов, которые уже покинули кэш и лежат в буфере плеера, даже 150 мс – поздно.

Во-вторых, инвалидация на масштабе платная. Первые 1 000 invalidation paths в месяц у CloudFront бесплатны; всё сверх – $0.005 за path. Wildcard-путь (/season-3/*) считается одним path, даже если матчит сто тысяч объектов, поэтому «инвалидировать префикс» почти всегда дешевле, чем «инвалидировать каждый сегмент». Akamai и Cloudflare публикуют корпоративные квоты, выше которых включается throttling.

В-третьих, инвалидированный объект не удалён из origin. Инвалидация очищает только кэш CDN. Если плохая версия файла всё ещё лежит на origin, самый следующий запрос после инвалидации затянет ту же плохую версию обратно в кэш – вы потратили инвалидацию впустую. Порядок всегда один: сначала чините origin, потом инвалидируете.

Рис. 1. Что инвалидация делает на самом деле – и чего она не делает.

Почему «purge URL» – неверный ход в стриминговом пайплайне

Команды статических сайтов тянутся к purge по умолчанию, потому что их модель контента это вознаграждает. Пост в блоге меняется → вы purge URL → мир видит свежую копию через секунды. Эта привычка плохо переносится в стриминг, потому что стрим – это не один URL, а дерево URL, форма которого меняется ежесекундно.

Типичный live HLS-стрим – это master playlist, четыре–шесть media playlists (по одному на ступень bitrate ladder), один init-сегмент на ренденцию, ключевой URI и хвост media-сегментов, который packager добавляет и удаляет каждые несколько секунд. Один зритель на интервале 4-секундных сегментов запрашивает около 30 разных URL в минуту. Событие на десять тысяч зрителей держит сотни тысяч объектов в кэше в любой момент.

Если у вас рефлекс «стрим сломан – purge», вас ждёт несколько неудобных фактов. Вы не можете очистить сегменты, которые уже в буферах плееров – они покинули CDN и лежат на устройстве зрителя. Скорее всего, вы не сможете purge быстрее, чем packager производит новые сегменты – на двухсекундных сегментах к моменту распространения глобального purge уже существует три новых сегмента, которые вы не purge. И массовый purge live-origin – одна из немногих операций, которые сами по себе могут сломать стрим: все плееры одновременно начнут revalidation, и пул соединений origin схлопнется.

Для статических VOD-ассетов математика мягче, но рефлекс остаётся ошибочным. Правильный вопрос почти никогда не «как мне сделать purge?». Он звучит так: «почему я оказался в ситуации, где purge необходим?». В здоровом пайплайне у этого вопроса немного ответов, и четыре других инструмента закрывают каждый из них дешевле.

Четыре инструмента, которые заменяют инвалидацию в стриминге

Считайте инвалидацию четвёртым выбором из этого списка, не первым. Первые три закрывают ~95% работы.

Инструмент 1 – короткий Cache-Control на том, что меняется

Манифесты в live меняются постоянно. Их надо кэшировать на edge как можно короче, чтобы плеер, который пришёл за свежим плейлистом, его действительно получил. Расхожее правило – половина target segment duration: стрим с целевой длительностью 6 секунд ставит max-age манифеста в 3 секунды; стрим с двухсекундными сегментами – 1. Apple HLS Authoring Specification формулирует ту же идею через привязку свежести плейлиста к моменту появления следующего сегмента.

Для media-сегментов – которые не меняются, как только появились – наоборот: Cache-Control: public, max-age=31536000, immutable. Директива immutable (определена в RFC 8246) говорит браузерам и CDN, что можно пропускать даже дешёвый revalidation round-trip. Связка «секундный манифест» + «годовой immutable-сегмент» – фундамент любой настроенной стриминговой CDN-конфигурации.

Инструмент 2 – версионированные имена файлов

Если сегменту действительно нужно измениться – обычно потому, что вы его перекодировали, починили вставку рекламы или убрали заикание – поменяйте ему имя. Объект season-3/episode-7/v1/segment-00042.m4s становится season-3/episode-7/v2/segment-00042.m4s. Манифест теперь указывает на путь v2; CDN видит URL, который никогда не кэшировал; origin отдаёт свежие байты; URL v1 сам выходит из кэша по TTL.

Именно этот паттерн позволяет ставить на сегменты max-age=31536000 без страха. Никогда не нужно инвалидировать сегмент, если его имя меняется каждый раз, когда меняются байты. Документация CloudFront прямо называет это first-class подходом. Bitmovin, Mux и AWS Elemental MediaPackage по умолчанию используют версионированные пути ровно по этой причине.

Математика: CDN, который отдаёт версионированные сегменты на cache hit ratio 99%, стоит примерно 1% от той же нагрузки без версионирования – потому что редкие промахи случаются только когда зритель первым спрашивает совсем новый URL. Команда, которая делает purge каждый деплой, платит эту разницу каждый раз.

Инструмент 3 – переписывание segment timeline

Для live-стримов сам манифест и есть примитив инвалидации. Packager убирает сегмент из окна media playlist (HLS) или из элемента SegmentTimeline (DASH) – и плееры перестают его запрашивать при следующем обновлении плейлиста. DASH-IF Implementation Guidelines описывают это прямо: «последний период может из неограниченной длительности стать фиксированной … или один или несколько периодов могут быть полностью удалены с конца MPD timeline». HLS использует EXT-X-MEDIA-SEQUENCE и скользящее окно записей EXTINF с тем же эффектом.

Для зрителя это незаметно. Плохой контент уходит из плейлиста; плееры перечитывают плейлист в пределах окна target-duration; через несколько секунд каждый новый зритель уже не знает про сегмент. Устаревшая копия сегмента в кэше CDN не имеет значения – её никто не просит.

Паттерн работает в live ровно по той причине, по которой не работает в VOD: live-манифест динамичен, VOD-манифест – нет. Для VOD остаётся инструмент 2 (версионирование) или инструмент 4 (настоящая инвалидация).

Инструмент 4 – реальная инвалидация кэша, но только когда первые три не помогают

Когда вы использовали инструменты 1–3, а плохой контент всё ещё доходит до зрителей прямо сейчас, инвалидация – правильный ответ. Реально подходящие сценарии узкие. Перечислим их ниже.

Рис. 2. Дерево решений, которое должно висеть в комнате до того, как кто-то нажмёт purge.

Когда инвалидация – правильный инструмент

Четыре сценария из реальной стриминговой практики.

Ротация ключа DRM на лету

Common Encryption (CENC, ISO/IEC 23001-7) и модель лицензий EME поддерживают ротацию ключей для непрерывного live-контента: ключ шифрования меняется по заданной частоте, сегменты после точки ротации шифруются новым ключом, и плееры заранее получают новую лицензию. Если ротация срабатывает раньше плана – обычно потому, что у подписчика отозвали entitlement – может понадобиться инвалидировать кэшированный ответ по URI ключа, чтобы следующий запрос ушёл за свежей лицензией. Сами сегменты инвалидировать не надо; ключ – да.

Операция узкая и хирургическая: purge только пути под EXT-X-KEY (HLS) или ContentProtection URL (DASH). Больше ничего. За секунды отрубите отозванного зрителя на следующем интервале запроса ключа, не задев стрим для остальных.

Takedown по DMCA, GDPR или «праву на забвение»

Если третья сторона подала DMCA-уведомление на кусок VOD, требование safe-harbour – удалить «expeditiously», обычно в течение 24 часов. Аналогичная срочность применима к запросам на стирание по GDPR и к контрактным takedown (спортивная лига убирает highlights ради регионального блэкаута).

Процедура: сначала убрать ассет на origin, потом инвалидировать wildcard-префикс на CDN, потом оставить ответ 410 Gone или 451 Unavailable на origin на случай, если кто-то достанет кэшированный URL в окне распространения. Версионирование тут не помогает – плохая версия была единственной, и «забыть v1» и есть требование целиком.

Развёрнутый баг в одном куске контента

Вы выкатили новую перекодировку 90-минутного фильма. QA замечает, что аудио сдвинуто на два кадра, но только на рендеренции 720p. Перекодирование – час. Час с битым файлом перед 50 000 зрителей вы ждать не можете.

Прагматичный ход: перекодировать в новый версионированный путь (инструмент 2), обновить манифест на новый путь и инвалидировать только манифест, чтобы кэшированная копия master-плейлиста на CDN обновилась мгновенно. Битые сегменты сами выйдут из кэша по TTL. Вы тратите одну инвалидацию, а не 800.

Live-стрим, который реально пошёл не так

Ведущий сказал то, что юристы не могут оставить в эфире. Нужно укоротить окно живого стрима и убрать запись VOD до её публикации. Live: остановить ingest, дать segment-timeline самому смыть сегменты за секунды. VOD: убрать ассеты с origin, инвалидировать wildcard на CDN, опубликовать чистую замену по новой версии.

Это канонический случай, когда любой другой инструмент слишком медленный – playlist roll-off закрывает live, wildcard-инвалидация закрывает VOD, версионирование закрывает замену.

Как крупные CDN реализуют инвалидацию в 2026

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

CDNНазвание операцииPath scopeTag / surrogate-keyВремя распространенияЦены
Amazon CloudFrontInvalidationPath + wildcard (/path/*)Cache Tag (апрель 2026) через response header10–15 мин (path); < 5 с P95 (tag)Первые 1 000 paths/мес бесплатно; $0.005 каждый сверх
Akamai (CDN / Adaptive Media Delivery)Fast PurgeURL, CP code, ARLEdge-Cache-Tag header~5 секундВключено в commit; rate-limited
CloudflarePurgeURL, prefix, hostname, всёCache-Tag header (Enterprise)< 30 секунд глобальноВключено в план; квоты на зону
FastlyPurgeURL или Surrogate-KeySurrogate-Key (бесплатно, все тарифы)~150 мс (instant purge)Включено в usage; batch API для ключей
Google Cloud CDN / Media CDNInvalidatePath + wildcardCache tag (response header)Несколько минутПервые записи бесплатно в месяц; usage сверх
Edgio (Verizon Digital Media)PurgeURL, list, dirSurrogate keysНесколько секундВключено; отдельные endpoint для live и VOD

Три нюанса стоит вынести на стенку.

Операция cache tag – то, что изменилось на этом рынке. Fastly выкатил surrogate keys в 2014-м и десять лет держал преимущество для стриминговых команд, которым нужно было сгруппировать тысячи сегментов одним тегом и потом purge группу одним запросом. Akamai и Cloudflare подтянулись следом. CloudFront добавил инвалидацию по Cache Tag в апреле 2026 года – пять секунд P95, через response-header, та же модель, что у Fastly. Стриминговые нагрузки на AWS, застрявшие в path-by-path инвалидациях, получили инструмент изящнее.

Время распространения – best-case, не worst-case. Цифры CloudFront в 10–15 минут для path-инвалидаций – документированное ожидание; обращения в AWS support показывают более длинные хвосты для дистрибутивов с большим числом edge. 150 мс Fastly – это реально, но применимо к узлам, которые получили purge: узел, который сейчас добавляется в POP, может отдавать stale дольше. Планируйте так, как будто хвост в два–три раза больше документированного.

Вас могут rate-limit. CloudFront троттлит при слишком большом числе инвалидаций в полёте (ошибка TooManyInvalidationsInProgress). Akamai и Cloudflare публикуют per-account per-minute caps. Команда, которая скриптует «purge на каждом деплое», рано или поздно упирается в стену во время реального инцидента.

Две ловушки, которые тихо ломают прод

«Ловушка – сначала origin, потом инвалидация. Инвалидация против всё ещё битого origin затянет плохой контент обратно в кэш, и вы потратите её впустую. Порядок всегда: сначала остановить отдачу плохого файла на origin, потом инвалидировать. Для takedown это значит сначала удалить ассет (или вернуть 410).»
«Ловушка – расползание scope wildcard. Инвалидация /series-7/* выглядит узко; инвалидация /*, нацеленная на одну опечатку, схлопывает глобальный cache hit ratio всех остальных ассетов дистрибутива на ближайшие полчаса. Собственная рекомендация CloudFront: «указывайте path только к тем файлам, которые действительно нужно инвалидировать». Поставьте guardrail в деплой-пайплайн, который отклоняет любой path с более чем одним замыкающим wildcard.»

Третью стоит упомянуть одной строкой, хотя она встречается реже: инвалидации против URL с параметрами подписи могут ничего не найти, если cache key включает подпись. Статья 6.3 – Cache keys for streaming разбирает половину этой проблемы про cache key полностью.

Рис. 3. Где каждый инструмент стоит на плоскости цена × латентность × точность.

Где здесь Фора Софт

Большинство наших клиентов в streaming, OTT, e-learning, телемедицине и видеонаблюдении сталкиваются с вопросом об инвалидации в первые полгода после запуска – обычно это takedown, поток ротации ключей или испорченный деплой ladder. Мы заводим playbook из четырёх инструментов в платформу с самого начала: короткий max-age на манифестах, immutable версионированные сегменты, segment-timeline-driven rolloff для live и охраняемый путь инвалидации, который требует и шага «origin починен», и ревью wildcard scope. Тот же каркас лежит под нашей работой по DRM и compliance, где разница между «мы покопали всё» и «мы почистили правильное» – это разница между чистым incident report и шестизначным счётом от CDN.

Ключевые выводы

  • Инвалидация медленная, платная и неточная – это инструмент последней надежды, а не шаг деплоя.
  • Короткие TTL на манифестах, immutable версионированные сегменты и segment-timeline rolloff закрывают ~95% работы.
  • Реальные сценарии для инвалидации: ротация ключей DRM, takedown, баг в одном ассете, отзыв live-стрима.
  • CloudFront добавил инвалидацию по cache tag в апреле 2026 – пять секунд распространения, surrogate-key стиль.
  • Сначала чините origin; потом инвалидируете; wildcard расширяйте только с ревью.
  • Wildcard /* почти никогда не правильный ответ; префикс /series-7/season-3/* обычно – да.

Что читать дальше

Призыв к действию

Поговорить со стриминговым инженером о политике инвалидации кэша для вашей платформы · Посмотреть кейсы в streaming, OTT и телемедицине · Скачать Cache Invalidation Playbook – одностраничный чек-лист с 4 инструментами, 4 сценариями, в которых инвалидация действительно нужна, и 6 проверками, которые on-call должен пройти до нажатия purge.

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.