Как CDN доставляет видео: origin, edge, кэш

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

TL;DR

Сеть доставки контента (content delivery network, CDN) – это слой, который размещает копии вашего видео на серверах рядом со зрителями, чтобы большинство запросов обслуживалось из ближайшего кэша, а не с единственного центрального сервера, называемого origin. Главное число, определяющее прибыльность стриминговой платформы, – это offload ratio: доля отданных байт, обслуженных из кэша CDN, а не забранных с origin, потому что каждый байт, который промахнулся мимо кэша, – это байт, за повторную отправку которого вы платите origin. Видео необычно хорошо подходит для этого: адаптивный стриминг режет каждую единицу контента на маленькие неизменяемые сегменты с одинаковыми URL для всех зрителей, поэтому одна кэшированная копия сегмента обслуживает тысячи людей. Эта статья на понятном языке объясняет, как запрос зрителя находит ближайший edge, почему сегмент так хорошо кэшируется, как числа cache-hit и offload напрямую превращаются в ваш ежемесячный счёт, и какие немногие ошибки тихо ломают и то, и другое.

Почему это важно

Если вы фаундер, продакт-менеджер или CTO стриминга впервые, то CDN – это место, где одновременно решаются и масштаб вашей платформы, и её маржа, и его легко принять за чёрный ящик, который просто включают. Это и есть дорогая ошибка. CDN, который offload'ит 99% ваших байт, и CDN, который offload'ит 90%, для зрителя выглядят одинаково – но второй отправляет на ваш origin в десять раз больше трафика и может тихо удвоить счёт, растущий каждый месяц вместе с аудиторией. Эта статья даёт вам ментальную модель, чтобы видеть разницу: что такое origin и edge на самом деле, как запрос маршрутизируется в кэш рядом со зрителем, почему сегменты видео кэшируются куда лучше обычной веб-страницы, и как прочитать схему доставки и заметить утечки. К концу вы сможете задать три вопроса, которые решают стоимость доставки: какой у нас offload ratio, как долго мы кэшируем каждый тип файла, и не заставляет ли что-то в нашей конфигурации кэш держать отдельные копии, которые он должен делить.

Две задачи CDN сразу: расстояние и повторение

Начнём с проблемы, потому что CDN – это ответ на две проблемы, надетые в одно пальто.

Первая проблема – расстояние. Ваши видеофайлы где-то лежат – на сервере или в хранилище, скажем, в Северной Вирджинии. Зритель в Токио, который обращается к этому серверу напрямую, вынужден слать каждый запрос и получать каждый байт через Тихий океан. Round-trip одного запроса на такое расстояние – примерно 100–150 миллисекунд, а стриминг видео – это не один запрос, а ровный поток запросов на один маленький кусок видео за другим, каждый ждёт предыдущего. Расстояние превращается в задержку, задержка – в крутящийся спиннер, и зритель уходит. Решение – держать копию видео на сервере в Токио, чтобы запрос токийского зрителя шёл несколько километров вместо нескольких тысяч, и round-trip падал со ~120 миллисекунд до однозначных чисел.

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

CDN – это глобальная сеть серверов (собственных машин компании, стоящих в дата-центрах и точках обмена трафиком по всему миру), которая существует, чтобы решать обе проблемы вместе. Она держит копии вашего контента рядом со зрителями (расстояние) и обслуживает многочисленные запросы к популярному контенту из этих локальных копий (повторение), чтобы к вашему origin обращались как можно реже. Фраза, которую стоит запомнить: близко и общее – контент держат близко к зрителю, и одну локальную копию делят многие.

Рисунок 1. Путь запроса. DNS и Anycast направляют каждого зрителя на ближайший edge. Cache hit обслуживается на месте; внутрь – через shield – к origin идёт только miss, и только один раз.

Origin и edge: два конца пути доставки

Два слова делают в этой статье основную работу, поэтому определим их точно.

Origin – это единственный авторитетный источник вашего видео: сервер или облачное хранилище, где лежит настоящая мастер-копия каждого файла. Концептуально origin один (его могут реплицировать ради надёжности, но это единый источник истины). Это место, где файл существует до того, как его впервые запросил хоть один зритель, и единственное место, откуда CDN может взять файл, которого у неё ещё нет.

Edge – это множество серверов CDN, разбросанных по миру, которые держат временные копии и собственно разговаривают со зрителями. Каждый кластер edge-серверов в одной локации называется точкой присутствия (Point of Presence, PoP) – буквально присутствием CDN в этой точке на карте. У крупного CDN сотни PoP в десятках стран. Когда мы говорим «зритель обслужен с edge», мы имеем в виду, что ближайший PoP отдал ему байты, не побеспокоив origin.

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

Как запрос находит ближайший edge

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

Первый – маршрутизация через DNS. Когда плеер хочет видеофайл, он сначала ищет адрес для вашего стримингового хоста (что-то вроде video.yourservice.com). Ответ на этот запрос контролирует CDN, и она отвечает адресом edge рядом со зрителем, а не адресом вашего origin. Частая форма – GeoDNS, где CDN читает примерную географию запроса и возвращает PoP в этом регионе. Это CDN вставляет себя в самый первый шаг, чтобы плеер с самого начала соединялся с edge.

Второй – маршрутизация через Anycast. Многие CDN дают целой группе edge-серверов один и тот же сетевой адрес и позволяют самой маршрутизации интернета доставить запрос к тому серверу, который ближе в сетевом смысле – меньше хопов, ниже задержка. Запрос зрителя адресован одному IP, и сеть передаёт его ближайшей машине, отвечающей на этот IP. DNS выбирает нужный регион; Anycast выбирает нужную машину внутри него. Вместе они означают, что плеер зрителя надёжно оказывается у ближайшего edge, и никто не настраивает устройство зрителя.

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

Почему видео так хорошо кэшируется: маленькие, одинаковые, неизменяемые сегменты

Вот факт, который заставляет экономику стриминга работать, и он напрямую восходит к тому, как упаковано современное видео.

Форматы адаптивного стриминга – HTTP Live Streaming (HLS, описан в IETF RFC 8216) и MPEG-DASH (ISO/IEC 23009-1) – не отдают видео одним гигантским файлом. Они режут каждую версию качества единицы контента на длинный ряд маленьких сегментов, в каждом несколько секунд видео, и публикуют небольшой текстовый индекс – манифест, который перечисляет эти сегменты по порядку. Плеер читает манифест, затем тянет сегмент за сегментом по обычному HTTP – тому же протоколу, что отдаёт веб-страницы. Как собираются эти файлы, мы разбираем в статье упаковка: CMAF, HLS и DASH из одного mezzanine, а механику самих протоколов – как устроены манифесты и сегменты HLS и DASH – в разделе Video Streaming в разборе HLS против DASH. Здесь важно то, что сегмент делает с кэшем.

Три свойства делают сегмент почти идеальным для кэширования. Во-первых, сегмент маленький – несколько секунд, а не несколько часов, – поэтому edge может держать их много и каждый отдавать быстро. Во-вторых, сегмент неизменяем: однажды записанные байты сегмента номер 47 заданного rendition никогда не меняются. Кэш обожает контент, который не меняется, потому что может держать и переиспользовать его, ни разу не спрашивая «он ещё актуален?». В-третьих, и это важнее всего, у сегмента один URL для всех зрителей. Когда десять тысяч человек смотрят один фильм в одном качестве, все десять тысяч плееров запрашивают ровно тот же seg_1080p_00047.m4s по ровно тому же адресу. Edge забирает его с origin один раз, сохраняет, и отдаёт остальные 9 999 запросов из этой одной сохранённой копии.

Это и есть глубокая причина, почему CDN может offload'ить почти весь трафик популярной единицы контента. Веб-страницу, персонализированную под каждого пользователя, кэшировать трудно, потому что каждая копия другая. Сегмент видео – противоположность: это одни и те же байты для всех, поэтому одна кэшированная копия делает огромную работу. Это же объясняет, почему «упаковать один раз» важно выше по конвейеру: если упаковка выдаёт один общий набор сегментов (современный подход CMAF), а не отдельные файлы под семейство устройств, каждый зритель rendition сходится к одному URL, и кэш держит одну копию вместо двух. Решения по упаковке, принятые неделями раньше, проявляются здесь как ваш cache-hit ratio.

Рисунок 2. Первый запрос сегмента промахивается и один раз забирает его с origin; edge сохраняет копию, и каждый последующий запрос того же URL – это cache hit. Одна копия обслуживает толпу.

Cache hit, cache miss и число, решающее вашу маржу

Теперь словарь, на котором идёт любой разговор о доставке.

Когда запрос зрителя приходит на edge и файл уже там, это cache hit – обслужен сразу, локально, без всякого трафика к origin. Когда файла нет, это cache miss, и edge вынужден забрать его с origin (или из внутреннего слоя кэша), прежде чем ответить. Hit'ы – это то, что вам нужно; miss'ы стоят вам задержки и трафика к origin.

Заглавная метрика – cache-hit ratio (CHR), доля запросов, обслуженных как hit. Если 95 из 100 запросов – hit'ы, ваш CHR равен 95%. Звучит просто и прячет ловушку, которую стоит понять, потому что это разница между «мне кажется, доставка здорова» и «я знаю, что она здорова».

Ловушка в том, что cache-hit ratio считает запросы, а запросы не одинакового размера. Запрос крошечного манифеста и запрос крупного высокобитрейтного сегмента оба считаются одним запросом, но переносят дико разное число байт, а платите вы за байты. Для видео метрика, которая реально отслеживает стоимость, – это offload ratio (origin offload), который Fastly определяет точно: «доля байт, отданных конечным пользователям, что были закэшированы внутри CDN (не забраны с origin), от всех байт, отданных конечным пользователям». Offload 100% означает, что каждый байт пришёл из CDN, и origin не отправил ничего. Cache-hit ratio считает, как часто вы попадаете; offload ratio считает, какую долю объёма данных вы удержали от origin. Для стриминговой платформы со счётом связано второе.

И вот мысль, которая удивляет почти всех, потому что арифметика нелинейна. Сдвиг cache-hit ratio с 90% на 95% не срезает «5%». Он режет долю промахов с 10% до 5% – он вдвое снижает трафик, бьющий по origin. Переход с 95% на 99% режет промахи с 5% до 1%, снижая нагрузку на origin ещё впятеро. Последние проценты offload стоят куда дороже первых девяноста – именно поэтому стриминговые инженеры одержимы ими, и поэтому улучшение cache-hit ratio на 1% способно сэкономить сервису масштаба Netflix петабайты трафика origin в год.

Арифметика вслух

Числа делают это конкретным, поэтому пройдём математику так, как реально текут байты зрителя.

Возьмём средний сервис: 100 000 активных зрителей, каждый смотрит около 10 часов в месяц при среднем битрейте доставки 5 мегабит в секунду (разумная смесь телефонов, веба и ТВ на адаптивной лесенке). Сначала – байты, отданные одному зрителю за месяц:

на зрителя = 5 Mbit/s × 10 ч × 3 600 с/ч ÷ 8 бит/байт
           = 5 × 36 000 ÷ 8
           = 22 500 МБ
           = 22,5 ГБ на зрителя в месяц

По всей аудитории:

всего доставлено = 22,5 ГБ × 100 000 зрителей
                 = 2 250 000 ГБ
                 ≈ 2,25 ПБ (петабайт) в месяц

Эти 2,25 ПБ – то, что edge отдаёт зрителям, и стоимость этих байт – ваш счёт CDN, повторяющийся egress-расход, который мы полностью разбираем в cost engineering для CDN: egress, коммиты и 95-й перцентиль. Но заметьте, что контролирует offload ratio: ту долю этих 2,25 ПБ, которую origin вынужден отправить, чтобы кормить edge'ы.

origin egress = всего доставлено × (1 − offload ratio)

при 90% offload:  2,25 ПБ × 0,10 = 225 000 ГБ с origin
при 95% offload:  2,25 ПБ × 0,05 = 112 500 ГБ с origin

Пять процентов offload – с 90% до 95% – убрали 225 000 → 112 500, ровно вдвое срезав месячный трафик origin. Если ваш origin – облачный бакет или сервер, берущий порядка $0,08 за ГБ отправки байт в CDN, то одна эта доля – это:

экономия = 112 500 ГБ × $0,08/ГБ ≈ $9 000 в месяц ≈ $108 000 в год

…и это до учёта compute и ёмкости origin, которые больше не нужно держать под удвоенную нагрузку. Суть не в точной сумме – она зависит от вашего origin и вашего контракта с CDN; суть в том, что число, на которое большинство команд никогда не смотрит – последние проценты offload – стоит шестизначной суммы в год на среднем сервисе, и больше с ростом. Offload – это рычаг; всё остальное в статье – про то, как его тянуть.

Рисунок 4. Origin egress для разобранного примера 2,25 ПБ по мере роста offload ratio. Каждый шаг вверх по кривой убирает бо́льшую долю трафика origin – один лишь шаг 90%→95% его вдвое снижает.

Time-to-live: как долго edge держит копию

Кэш не может держать каждую копию вечно, а для некоторых файлов и не должен. Правило, которое задаёт, как долго edge держит файл, прежде чем перепроверить, – это его time-to-live (TTL), и его задаёт та же HTTP-машинерия кэширования, что крутит весь веб, – стандартизованная в IETF RFC 9111.

Механизм – небольшая инструкция, которую ваш origin прикрепляет к каждому файлу, заголовок Cache-Control. В терминах самого RFC 9111 edge CDN – это shared cache (общий кэш): «кэш, который хранит ответы для переиспользования более чем одним пользователем», а директива, говорящая общему кэшу, как долго файл остаётся свежим, – это s-maxage (RFC 9111 §5.2.2.10), с более знакомым max-age как запасным вариантом. Когда время свежести истекло, кэшированная копия «протухла», и edge ревалидирует её у origin перед повторной отдачей. Так что ваш origin не во власти CDN – он диктует поведение кэша файл за файлом через эти заголовки.

Видео чётко делится на два типа файлов с противоположными нуждами, и правильное разделение – одно из самых рычажных действий, которые вы можете предпринять.

Сегменты надо кэшировать долго. Медиасегмент неизменяем – сегмент 47 всегда сегмент 47, – поэтому можно безопасно велеть edge держать его сутками и дольше. Долгие TTL сегментов и поднимают ваш offload ratio, потому что сегмент, забранный один раз, продолжает обслуживать зрителей всё то время, пока единица контента популярна.

Манифесты зависят от того, live это или on-demand. Для video-on-demand манифест фиксирован после публикации, поэтому его тоже можно кэшировать долго. Для live манифест переписывается каждые несколько секунд по мере появления новых сегментов, поэтому кэшировать его слишком долго прямо вредно: edge, отдающий протухший live-манифест, вручает плеерам список, в котором нет новейших сегментов, и воспроизведение стопорится. Правило большого пальца – кэшировать live-манифест не дольше примерно половины длительности его сегмента: live-стрим с шестисекундным сегментом хочет, чтобы его манифест кэшировался около двух-трёх секунд, достаточно свежим, чтобы всегда перечислять последний сегмент.

Вот почему «кэшировать всё агрессивно» неверно для live, а «не кэшировать ничего на всякий случай» неверно для всего: сегмент и live-манифест требуют противоположных политик. Механизм, решающий, какая кэшированная копия отвечает на запрос, – cache key и подписанные/токенизированные URL, гейтящие доступ, – это отдельная тема, разобранная в edge-кэширование, cache keys и токенизированные URL.

Рисунок 3. Сегменты неизменяемы и кэшируются долго; VOD-манифест фиксирован и кэшируется долго; live-манифест меняется каждые несколько секунд и должен кэшироваться лишь кратко. Одна платформа, противоположные политики.

Когда edge промахивается: shield'ы, тиры и наплыв на премьере

Cache miss надо чем-то заполнить, и наивный ответ – каждый edge в мире идёт прямо к вашему origin при промахе – это ровно то, как live-премьера кладёт вашу платформу.

Представьте новый эпизод, выходящий в 20:00 для глобальной аудитории. В первую секунду edge'ы в десятках регионов разом обнаруживают, что у них ещё нет сегмента 1, и все разом разворачиваются и просят его у origin. Этот синхронный поток – thundering herd («гремящее стадо»), и незащищённый origin может рухнуть под ним ровно тогда, когда смотрит больше всего людей.

Защита – слой между edge'ами и origin под названием origin shield (или средний кэш, или tiered caching). Вместо того чтобы каждый edge разговаривал с origin, все edge'ы региона направляют свои промахи через один назначенный кэш-shield, и уже shield говорит с origin. Shield добавляет один приём, который меняет всё: request collapsing (схлопывание запросов). Когда сотня edge'ов в один миг просит у shield сегмент 1, а его у shield ещё нет, shield шлёт один запрос к origin, ждёт и отвечает всем ста edge'ам из единственного ответа. Origin видит один забор там, где иначе увидел бы сотню – по сообщениям, это срезает запросы к origin на 90% и более во время наплыва. Shield поднимает ваш offload ratio и в обычной работе, потому что два edge'а, которые оба промахнулись, оба могут быть обслужены shield'ом без двух походов к origin – отчасти поэтому простое число edge-cache-hit способно недооценивать, сколько работы реально делает CDN.

Это и есть архитектура, позволяющая платформе пережить премьеру, которую нельзя переиграть, и у неё своя глубина: см. origin и origin shielding про дизайн и доставку live-событий и наплыв на премьере про операционный плейбук. Когда одного CDN мало – ради устойчивости или для торга по egress – вы запускаете несколько за слоем выбора, архитектуру multi-CDN следующей статьи, чья механика переключения на уровне протокола живёт в подробном разборе multi-CDN раздела Video Streaming.

Есть ещё более близкий тир, о котором стоит знать, потому что он показывает, где эта логика заканчивается. Крупнейшие стримеры заталкивают кэши аж внутрь интернет-провайдеров: программа Netflix Open Connect размещает собственные кэш-устройства в сетях провайдеров, наполняя их контентом в часы спада, чтобы единица контента пересекла границу провайдера один раз и дальше обслуживалась каждому абоненту этой сети изнутри. Это тот же принцип, что и региональный PoP – ближе и общее – доведённый до физического предела. Большинство платформ никогда это не построят; вы арендуете коммерческий CDN, который сделал эквивалент. Но это самая ясная иллюстрация идеи всей статьи: чем дальше вы толкаете общую копию к зрителю, тем меньше вообще приходится делать origin.

Как читать конфигурацию CDN: чек-лист возможностей

Когда вы оцениваете CDN или читаете собственную конфигурацию, вот возможности, которые решают стоимость и устойчивость доставки видео. Колонка «Почему важно для видео» – это перевод из фичи в последствие.

ВозможностьЧто этоПочему важно для видео
Глобальный охват PoPEdge-локации в регионах ваших зрителейРасстояние = задержка; зритель вдали от любого PoP буферизует независимо от offload
Origin shield / tiered cacheСредний кэш, схлопывающий промахиЗащищает origin от наплыва на премьере и поднимает offload
Соблюдение долгих TTL сегментовEdge держит неизменяемые сегменты суткамиГлавный драйвер высокого offload ratio
Кэш-контроль по файламРазные TTL для сегментов и live-манифестовLive'у нужен короткий TTL манифеста; сегментам – долгий, одна политика не подходит обоим
Отчётность по байтам/offloadВидимость offload по байтам, не только request CHRRequest CHR прячет картину стоимости для крупных файлов
Поддержка токенизированных URLПодписанные URL, которые кэш всё равно ключует верноКонтроль доступа без разрушения кэшируемости
Предсказуемые цены egressМодель цен, которую можно посчитать и закоммититьEgress – доминирующий повторяющийся расход; сюрпризы ломают маржу

Таблица 1. Возможность полезна, только если включена и настроена под видео. Самый частый сбой – не отсутствие фичи, а присутствующая фича, оставленная на дефолте для веб-страниц, который тихо душит offload ratio.

Частая ошибка: кэш, который едва кэширует

Самая дорогая ошибка доставки невидима с места зрителя: платформа, чей offload ratio сидит на 70%, когда должен быть 97%, платит за втрое-вчетверо больший трафик origin, чем нужно, навсегда – при том что каждое видео играет нормально.

Обычная причина – cache key, загрязнённый шумом на каждого зрителя. Если ваши URL сегментов несут query-строку, разную у разных зрителей – session-токен, аналитический ID, cache-buster, добавленный плеером, – и CDN включает эту query-строку в cache key, то edge считает seg_00047.m4s?user=alice и seg_00047.m4s?user=bob двумя разными файлами и хранит отдельную копию на каждого зрителя. Свойство, делавшее видео прекрасно кэшируемым – один URL для всех – разрушено, и ваш offload обваливается к нулю ровно на самом смотримом контенте. Лечение – убрать из cache key параметры конкретного зрителя, чтобы все зрители rendition сходились к одному кэшированному объекту; подробнее в edge-кэширование, cache keys и токенизированные URL.

Три родственника ходят рядом. Первый – TTL, оставленные на веб-дефолтах: короткие окна свежести для меняющегося HTML, применённые к неизменяемым сегментам, так что edge зря перепроверяет origin, и offload проседает; ставьте долгий s-maxage на сегменты осознанно. Второй – кэширование live-манифеста так же долго, как сегмента, что стопорит live-воспроизведение отдачей протухшего списка сегментов; кэшируйте live-манифест на секунды, не на часы. Третий – единственный origin без shield'а, который работает в тестах и падает на первой же реальной премьере; ставьте shield заранее, а не потом. Ни одна из этих ошибок не выдаёт ошибки. Все они проявляются только в счёте и в отчёте об инциденте – поэтому offload ratio заслуживает собственного дашборда.

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

Доставка – это место, где повторяющийся расход стриминговой платформы выигрывается или проигрывается, и разница между offload ratio 90% и 98% – это разница между счётом CDN, растущим вместе с аудиторией, и счётом, растущим вдвое быстрее, – задолго до того, как зритель хоть что-то заметит. Фора Софт с 2005 года строит ПО для видеостриминга, OTT/Internet TV, e-learning, телемедицины и видеонаблюдения – 250+ запущенных проектов для 400+ клиентов, – и эта работа сосредоточена ровно на такой инженерии масштаба и стоимости: проектировании архитектур origin и кэша так, чтобы сегменты кэшировались долго, манифесты кэшировались верно для live и VOD, cache key оставался чистым, а shield стоял между премьерой и вашим origin. Когда медиакомпании нужна схема доставки, чья экономика переживает реальную, растущую аудиторию по регионам, именно эта инженерия origin-и-кэша – то, что мы приносим.

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

  • CDN решает расстояние и повторение: копии видео близко к зрителям и общие для многих.
  • Origin – единственный истинный источник; edge – глобальный кэш, говорящий со зрителями.
  • Видео хорошо кэшируется: сегменты маленькие, неизменяемые и с одним URL для всех.
  • Offload ratio – байты из кэша, не запросы – это число, связанное со счётом.
  • Сдвиг cache-hit ratio 90%→95% вдвое режет трафик origin; последние проценты ценнее всего.
  • Сегменты – долго, live-манифесты – секунды, shield – до премьеры.

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

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

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