VK Видео: архитектура сервиса на основе пользовательских метрик

Когда говорят о выборе архитектуры IT-системы, почти всегда упускают один ма-а-аленький нюанс: мы делаем продукты для пользователей, не для себя. А пользователям совершенно неважно, какая у сервиса архитектура. Никто в отзывах не ставит звёздочки за event-driven подход или классную реализацию service mesh — разве что в редких случаях, когда речь о продуктах для разработчиков. 

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

91f62ad9de87c4eae0a58cfe73d55afd.png

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

Искать связь между архитектурой и пользовательским опытом будем на примере VK Видео. Эта платформа объединяет все видеосервисы компании VK, содержит 5 000 серверов, хранилище на 1 эксабайт данных, обеспечивает до 2,5 млрд просмотров видео в сутки и 4 Тбит/с трафика. Чтобы проследить формирование платформы, оглянемся назад и посмотрим, с чего всё начиналось. А затем обобщим главные пользовательские метрики и разберём основные составляющие архитектуры:

История одного видеосервиса

Архитектура нашей платформы начала складываться почти десять лет назад. Картинка ниже — это артефакт из 2013 года: тогда в Одноклассниках мы создали такую схему архитектуры. И теперь это почти единственная документация, которая сохранилась с тех пор. 

984f12d2afb936719c2053d571d7b28c.jpeg

Тогда у нас было 10 млн ежемесячной аудитории, которые генерировали 50 млн просмотров в сутки и 100 Гбит/с трафика. Все видео умещались в хранилище на 5 Пбайт, а для обслуживания платформы хватало 200 серверов. Это несколько процентов от сегодняшних объёмов, но в то время это были неплохие нагрузки, которые уже требовали серьёзного подхода к разработке. 

За почти десять лет развития платформы мы сделали многое. Например, всего на год позже YouTube поддержали 4К, сделали сервис трансляций и показали рекордный стрим на 3 Тбит/сек (подробности см. в этом докладе). На этой же базе создали сервис коротких вертикальных видео VK Клипы — раньше YouTube Shorts и подобных форматов у других социальных сетей.

В 2021-м объединили видеоконтент из соцсетей и сервисов VK и официально запустили VK Видео. С момента запуска уже вышло много продуктовых релизов: ML-автосубтитры, нейросетевая технология NeuroHD для повышения разрешения и FPS, офлайн-просмотр, приложение для SmartTV и другие технологии, о которых ещё поговорим в этой статье.

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

  • пользователи загружают контент на наши серверы;  

  • мы его как-то преобразуем, чтобы потом эффективнее показывать другим пользователям;  

  • сохраняем и раздаём.

Она же — универсальная архитектура контентного сервисаОна же — универсальная архитектура контентного сервиса

У любого видеохостинга, сервиса для постинга фотографий или обмена музыкой примерно такая же структура. Но некоторые из них нравятся пользователям больше. Бывает, что мы бьёмся над качеством технических решений, а люди всё равно предпочитают конкурентов, у которых под капотом всё «на проволоке и изоленте». В этой статье попробуем разобраться, почему так и как связать счастье пользователей с техническими метриками. 

Метрики пользовательского опыта

Есть разные метрики, которые помогают отслеживать, насколько аудитория довольна сервисом. Например, CSat (Customer Satisfaction Score) — это когда пользователь ставит приложению звёздочки в сторе; NPS (Net Promoter Score) — когда советует (или наоборот, не советует) сервис друзьям и коллегам; CSI (Customer Satisfaction Index) — баланс ожиданий, полученной пользы и качества; индекс TRI*M учитывает опыт использования, готовность рекомендовать продукт и продолжать работать с ним, а также мнение о преимуществах сервиса перед альтернативами. Все эти показатели можно и нужно измерять, проводя опросы.

Ещё есть множество технических метрик, на которые завязаны мониторинги. У всех нас прописаны SLI/SLO, мы следим за availability своих сервисов, измеряем и стараемся уменьшать latency, потерю пакетов, метрики приложения вроде PLT, TTI и LCP.

8b0081fd5904f820af2797b9b5ca7e60.png

Свести всё это вместе можно через QoE — Quality of experience. Это обобщающая метрика родом из телекома. Она учитывает разные факторы, влияющие на восприятие системы целиком: от технических (задержек и качества сети) до характеристик устройства и самого пользователя (страна, образование). QoE обычно отображается в engagement (вовлечённости) и коррелирующем с ней счастье пользователя. Очевидно, что никто не станет много и часто пользоваться сервисом, который не устраивает. Но при этом счастье и удовлетворённость зависят ещё и от цены, бренда и других факторов. 

QoE сильно коррелирует с продуктовыми метриками. Отслеживая её, можно увидеть, какие изменения в архитектуре сервиса и технологические решения влияют на мнение пользователей о продукте. Самый простой способ измерять QoE — это собирать MOS (mean opinion score): периодически просить пользователей оценить сервис по пятибалльной шкале, от «отлично» до «плохо».

Если собрать достаточно много оценок в разных ситуациях, то можно попытаться найти корреляцию удовлетворённости пользователя и некоторых технических параметров. Например, в исследовании о QoE-driven видеостриминге в LTE-сетях приводится зависимость MOS от битрейта видео.

4e832dd6c22de67db16076ab108d75fa.png

В другой статье MOS измеряют относительно FPS. Результаты холиварные: разница между 15 и 30 FPS очень существенная, повышение с 30 до 60 FPS даёт небольшой прирост MOS, а FPS больше 60 практически не улучшает пользовательский опыт. Но эти данные за 2011 год. Возможно, с тех пор мы стали придирчивее и лучше замечаем разницу в кадровой частоте.  

110e662ee8e5ff42a5e22fd97429e400.png

Пользовательские ожидания год от года растут: то, что недавно было стандартом качества, скоро может стать неудовлетворительным. А ещё в определённых обстоятельствах метрики могут конфликтовать между собой. Например, при недостаточной пропускной способности сети нужно искать компромисс между битрейтом и FPS — и находить баланс тоже лучше через метрики и эксперименты.

QoE также применима к веб-сервисам (см. статью Waiting times in quality of experience for web based services). В частности, можно увидеть, что к разным видам действий немного разные требования по Page Load Time (PLT): картинки должны загружаться мгновенно, а результатов поиска пользователи готовы секундочку подождать. Но в любом случае после ожидания больше 200 мс оценки начинают проседать. 

aabceeed71b931e10802d51918ac8c52.png

Хорошие показатели QoE не гарантируют успех у пользователей, но без них завоевать аудиторию вряд ли получится. Дальше на примерах рассмотрим основные составляющие видеоплатформы и ключевые характеристики, влияющие на QoE.

Загрузка: скорость

Требования пользователей к загрузке и скачиванию файлов полностью описывает мультик двадцатилетней (!) давности.

Но с тех пор сильно изменились и размеры файлов, и ожидания от качества и скорости загрузки. Загрузка обязана быть отказоустойчивой и возобновляемой — как этого добиться, рассказываем в другой статье. Остаётся вопрос скорости: быстро — это как?  

Метрики говорят, что если небольшой файл не загружается за 5–7 секунд, то пользователь начинает нервничать. На графике ниже пример с файлом в 25 Мбайт: сейчас это короткое видео, несколько фотографий или небольшая презентация. А ещё видно, что и для больших объёмов ждать 2 минуты никто не хочет.

003ec177b0769ddc0dce719c36a5c26f.png

Причём рядовой пользователь не хочет и не должен разбираться, на чьей стороне проблема: дело в неустойчивой сети, слабом телефоне или сервис действительно плохо работает. Человек, скорее всего, просто останется недоволен приложением. 

Чтобы ускорить upload, нужно эффективнее использовать пропускную способность. Вариантов для этого не так много: HTTP/1.1, HTTP/2 и HTTP/3. 

HTTP/1.1 и загрузка чанками

Работает так: разбиваем файл на чанки; отправляем целиком первый блок данных POST-запросом, ждём ответа 200 OK (здесь появляется задержка в RTT — Round Trip Time), затем отправляем следующий блок новым POST-запросом. 

Допустим, чанки размером по 4 Мбайта. Тогда, чтобы загрузить файл в 1 Гбайт, понадобится 256 лишних RTT, то есть 38 секунд при RTT = 150 мс (это, в принципе, немного: RTT может быть и 400 мс).

HTTP/2 и мультиплексирование

Конечно, если использовать мультиплексирование и в одно соединение запихнуть несколько потоков, будет быстрее.

e1a33d8f25483091d6384a32e2cd9a2b.png

Проблема HTTP/2 в том, что, чем больше потеря пакетов, тем сильнее снижается эффективность утилизации сетевого канала (подробнее в статье о сетевом стеке). 

HTTP 1.1 и параллельная загрузка

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

ad2b079c708c8bcce6d863db194853bc.png

Причём такой способ как минимум не проигрывает относительно HTTP/3. Скорость загрузки будет либо такой же, либо даже выше — за счёт большего количества подключений и «не fair» распределения канала связи. К тому же TCP всё равно всегда нужен для фолбэка. 

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

3b6fb0f85918e48340a0abfbf035ecb1.jpeg

Что может пойти не так на этапе загрузки?

На объёмах до 14 млн новых роликов в сутки всё, что может пойти не так, рано или поздно стрельнёт. Для примера допустим, что мы в параллельной загрузке раздаём чанки потокам по одному, как игральные карты. То есть первый поток грузит первый, пятый, девятый чанки и так далее, второй — второй, шестой… Тогда, если один из потоков устанет и перестанет работать, получится слишком много дыр, список которых для ретрая просто переполнит HTTP header.

a627560004e4ac63b150377c4c8008bf.jpeg

Максимальный размер HTTP header зависит от того, что вы используете — nginx или Apache. Но он в любом случае ограничен и может переполниться. Поэтому мы раздаём чанки потокам, по сути, последовательно — то есть ближайшие неотправленные. 

Другая проблема возникает с DNS-запросами — она редкая, но коварная. Оказывается, что два DNS-запроса, отправленные подряд, могут зарезолвиться на разные IP и в разные дата-центры из-за TTL. Тогда, даже с учётом распределённого хранения состояния, загрузка становится медленнее — и в принципе возможно, что одни и те же чанки будут грузиться в разные дата-центры. При построении отказоустойчивой высоконагруженной системы нужно предусматривать и такие ситуации и уметь их разрешать.

В комплексе все меры, повышающие надёжность и ускоряющие загрузку, увеличили QoE нашего сервиса. Мы получили +7% успешных загрузок, то есть существенно повысили вовлечённость аудитории. 

Специфика видеофайлов

Видео состоит из кадров. Если передавать его просто как набор полных кадров, то для 4К-видео в 60 FPS потребуется сеть с пропускной способностью на 18 Гбит/с. Это может обеспечить HDMI-кабель длиной несколько метров, но не обычная пользовательская интернет-сеть. Поэтому видео кодируется так, чтобы только часть кадров передавать в полном разрешении, а остальные кодировать через изменения относительно предыдущих. Так для 4К-видео становится достаточно 50 Мбит/с. 

Каждые несколько лет появляется новый кодек, который примерно в два раза эффективнее предыдущего по степени сжатия, но и вычислительно затратнее. VP8, VP9 — открытые стандарты, которые разрабатываются в основном в Google. H.264, H.265, H.266 — лицензируемые форматы. AV1 разрабатывается «Альянсом за открытые медиа», в который входят AMD, Nvidia, Apple, Google, Microsoft и многие другие компании. 

Кодек

Год

Эффективность относительно предыдущего

Аппаратная поддержка на сервере

Android

iOS

decoder

encoder

decoder

encoder

H.264

2003

baseline

GPU, CPU

HW

HW 3.0+

HW

VP8

2008

0%

CPU

HW/SW

SW 4.3+

SW

H.265/HEVC

2013

50%

GPU, CPU

5.0+

SoC, iOS11 (faceTime)

VP9

2012

CPU, GPU 

Snapdragon, Exynos

AV1

2018

35%

CPU, GPU 

Exynos

coming soon

H.266/JVET

2021

50%

Источник и детальные сравнения видеокодеков: compression.ru/video/codec_comparison/index.html

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

Знакомые расширения файлов: MP4, Matroska, 3GP — это контейнеры. Спецификации контейнеров описывают формат по размещению медиаданных в одном файле. Контейнеры, по сути, содержат видео и аудио, упакованные разными способами, чтобы их было можно было перематывать или запускать с середины.

6fa232e4a1b89329ec8fe0e381dd0574.jpeg

Транскодирование: качество

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

c007d8f112e96ab43e6d2e27845c9f2c.jpeg

Главное требование — сжимая видео, сохранить адекватное разрешению качество. 

Для оценки качества видео есть такие метрики, как PSNR, SSIM, VMAF. 

PSNR — пиковое отношение сигнала к шуму. Проще всего его определять через среднеквадратичную ошибку. SSIM, или индекс структурного сходства, в отличие от PSNR, отражает «восприятие ошибки» благодаря учёту структурного изменения информации. VMAF (Video Multimethod Assessment Fusion) разработана в Netflix в 2016 году, чтобы предсказывать субъективное восприятие качества видео.

По большому счёту, все они пытаются смоделировать то, как сжатую картинку или видео оценил бы человек. Ниже на графиках видим: по горизонтальной оси MOS-оценка для нескольких образцов из разных доменов, по вертикальной — смоделированная. Чем меньше расстояние от точек до диагонали, тем ближе предсказанная и фактические субъективные оценки. И значит, точнее метрика.

9f40491f0296474af19ef66726fe5ff1.jpeg

Судя по этим диаграммам, VMAF — лучшая метрика для оценки качества видео. Правда, это диаграммы из whitepaper от Netflix, в которой VMAF как раз и презентуется. По другим независимым тестам (например, здесь) корреляция VMAF с MOS не такая уж хорошая. Оттуда же следует, что лучше всего методика Netflix применяется к видео в высоком разрешении — что логично и соответствует их доменной области онлайн-кинотеатра.

Коэффициент корреляции объективных метрик оценки качества видео и субъективных по MOS для видео в разном разрешении.Коэффициент корреляции объективных метрик оценки качества видео и субъективных по MOS для видео в разном разрешении.

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

За неограниченное время с неисчерпаемыми вычислительными ресурсами можно, наверное, добиться того, что транскодированное видео будет неотличимо от исходного. Но мы помним, что пользователи не любят ждать. Поэтому в своём пайплайне зафиксировали допустимое окно PSNR в 43–44 дБ и в этих рамках стараемся ускориться.

c25e3cec8994755dfbf2076fbd104f11.jpeg

Мы отказались от стандартного и вполне рабочего варианта реализации транскодирования с помощью FFmpeg. Вместо него написали поверх libav свой транскодер и используем аппаратный энкодер Nvidia NVENC для GPU — подробнее о наших изменениях относительно FFmpeg рассказываем в этом видео. 

В результате всех этих ухищрений получили прирост по скорости обработки в FPS на 30%. Также улучшили время процессинга: обработка 15-минутного видео размером 1 Гбайт занимает 6 минут на GPU и 8 минут на CPU —, а у конкурентов примерно 10 минут.

Мгновенная доступность

Мы ускорили загрузку и транскодирование — и увидели, что наши пользователи могут начинать смотреть видео быстрее, чем на других сервисах. И, было дело, обрадовались этому результату. Но фидбэк авторов был неутешительным: «Почему моё видео не доступно сразу же после того, как я его загрузил? Почему его могут посмотреть только через несколько минут?» И действительно: например, для новостей это может быть критично. 

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

В целом процесс довольно простой: читаем заголовок файла; находим и вычитываем нужные семплы; скармливаем их транскодеру на базе ffmpeg; передаём результат на сервер, раздающий сегменты видео. Сейчас мы работаем только с MP4, так как больше 80% видео к нам загружают именно в нём. Если от пользователя приходит другой формат, например mkv, то ремуксим его в MP4 — это чуть дольше, но всё равно быстрее полного транскодирования. 

Несмотря на то что идея простая, мы пришли к ней далеко не сразу — думали, что на лету резать терабайты видео будет невозможно. Но за счёт кеширования нагрузка почти не возрастает: тратим примерно 4 000 vCore. А бонусом к качеству клиентского сервиса ещё и экономим до 40–50% места в хранилище — во всех разрешениях храним только популярные видео, для остальных роликов достаточно исходного. С точки зрения баланса ресурсов и улучшения сервиса мгновенная доступность оказалась очень выгодным решением.

Раздача: надёжность, скорость, качество

Большая часть трафика из общих 4 Тбит/с приходится на небольшой процент популярного контента. Поэтому сервер раздачи по сути является большим кеширующим сервером. Есть кеширование на разных уровнях: в оперативной памяти (LRU — least recently used) и на диски (LRU и FIFO — first in, first out), на центральном сервере и на CDN и т. д. Кеширование защищает хранилище от перегрузок.

Структура сервера раздачи.Структура сервера раздачи.

Кешируем не целиком файлы, а блоками по 256 Кбайт. Обязательно первый кадр, так как начало видео смотрят больше, чем остальную его часть. А также превентивно качаем вперёд по K блоков, не дожидаясь обращения. 

Чтобы использовать сервер эффективно и раздавать на скорости 100 Гбит/с, мы перенастроили сетевой стек, работу с прерываниями и NUMA. Подробнее рассказываем в статье об отказоустойчивости нашей архитектуры.

12ffee423d6013485499541e0924dda7.jpeg

Балансировка

Для раздачи мы используем порядка 200 серверов — это немного на фоне их общего количества в 5 000. Трафик на отдачу в вечернее время сейчас составляет около 4 Тбит/с, но, естественно, мы должны быть готовы к его кратному росту. Поэтому балансировка для нас очень важна и требует тщательного выбора архитектурных решений. 

Чтобы обеспечить эффективную раздачу с точки зрения ресурсов и скорости доставки данных до пользователей, используем согласованное хеширование (consistent hashing) по всему контенту. Оно устроено так, что по сути каждый сервер отвечает за определённый контент. Если он выйдет из строя, не потребуется переназначать все ключи.  

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

3921a26b14f6d916ddb06100a9d01c62.jpeg

У серверов раздачи обязательно есть лимиты на нагрузку. Если на сервере слишком высокая нагрузка на CPU, память и диски — из-за DDoS или по другим причинам, — то сервер нужно разгрузить, перенаправляя трафик на другие. 

Рассмотрим на примере, почему нельзя перегружать серверы. Плеер кеширует видео и заранее скачивает сегменты суммарной длительностью, например, в минуту. Допустим, на сервере раздачи случилась какая-то локальная проблема — например, мигнула сеть у провайдера. Весь буфер израсходовался на то, чтобы нивелировать перебои в скачивании. В ответ плеер начинает активнее скачивать сегменты, чтобы заполнить буфер. Если видео популярное и проблема задевает сразу многих клиентов, то сервер раздачи получает удар трафиком: сразу много запросов на быстрое скачивание. 

64ee4018299d5174d54a372c3fdbef21.gif

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

db45f8ed87a0ddf0324c7cfecc459403.jpeg

Защищаться нужно на уровне сервиса. Если сервер не справляется с нагрузкой, можно не выводить его сразу из оборота, а деградировать. Сервер должен сам защищаться от пользователей. Мы используем throttler и не отдаём видео быстрее, чем ×3 от скорости просмотра. Дальше задача плеера — разобраться, что делать, и при необходимости понизить качество воспроизведения. Для этого есть алгоритмы адаптивного стриминга. 

0f0e53163d51d236c7f98d5eb8f758ed.jpeg

Этот же подход помогает защищаться от DDoS — очень трудно «задидосить» систему, рассчитанную на десятки Тбит/с. Если какой-то сервер подвергается DDoS-атаке, мы выводим его из ротации и продолжаем спокойно обслуживать пользователей. Злоумышленники атакуют следующий сервер — у нас в запасе есть ещё и так далее. 

CDN

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

42f23cf1c6ee98e2cf33487a84c60b70.png

В нашей сети больше 50 узлов, расположенных в разных регионах России и мира. Но само по себе количество узлов CDN не гарантирует быстрой доставки. Нужно ещё отправить запрос пользователя на тот сервер, с которого действительно будет быстрее загрузить контент. 

Базово есть два типа реализации CDN: GeoDNS и AnyCast CDN. 

2b2912199315b358ace3d45397771ed7.jpeg

При GeoDNS общий хост превращается в IP-адрес сервера раздачи на нашем DNS-сервере. Когда пользователь запрашивает видео или любые другие данные по ссылке вида https://video.mycdn.me/? id=12345&q=1080, мы независимо от расположения отдаём один адрес — https://video.mycdn.me/. Резолвим его на конкретный сервер на уровне нашего DNS, в идеале на ближайший к пользователю.

Есть несколько проблем с этим подходом:  

  • Если какой-то из DNS Recursor на пути запроса не поддерживает EDNS, до нашего DNS-сервера не долетит IP-адрес клиента. Тогда мы не сможем вычислить ближайший сервер и вернём центральный. EDNS осознанно выключен, например, на крупном DNS-резолвере 1.1.1.1. Утверждается, что как раз для того, чтобы не раскрывать адрес пользователя и обеспечить приватность. 

  • DNS-сервер видит только доменное имя, но не весь запрос. Это делает неэффективным кеширование. Вот почему: мы делим контент на партиции, а партиции фиксируем за конкретными серверами на площадках. И все запросы за видео id=12345 из примера внутри площадки стоит отправить на один и тот же сервер —, но на уровне DNS-запросов это не решить.

  • Есть проблемы с оперативным выводом серверов из ротации, так как DNS-ответы кешируются серверами. 

Такая схема хорошо работает для статики: CSS, JS, небольших картинок. То есть когда все серверы хранят одно и то же и нет проблем с партиционированием. Но подход плох для тяжёлого и часто обновляющегося контента типа видео.

При AnyCast CDN общий хост превращается в один адрес сервера раздачи. Ближайший сервер определяется уже на сетевом уровне в момент установки соединения — этим занимаются маршрутизаторы провайдеров. То есть, как и GeoDNS, мы всё ещё выдаём общее доменное имя и https://video.mycdn.me/ превращается в условные 12.3456.78. Но на сетевом уровне трафик до этого IP-адреса, когда он приходит в нашу AS (автономную систему), направляется на ближайший сервер. 

Так за одним IP может скрываться несколько разных серверов. Это решает некоторые проблемы GeoDNS, но и привносит новые:

  • нужны хитрые манипуляции на сетевом уровне — например, поддерживать TCP-соединения;

  • требуется, чтобы все серверы были в нашей AS —, а с провайдерскими площадками такое невозможно. В нашем CDN есть как собственные дата-центры, так и провайдерские.  

Поэтому у нас своё решение и мы всегда выдаём ссылки на конкретный хост конкретной площадки, который закреплён за запрашиваемой партицией видео. Определяем его исходя из IP-адреса пользователя и данных, которые нам сообщают провайдеры (список подсетей по BGP). Благодаря нашему BGP-коллектору маршрутов мы точно знаем, какой длины AS path между клиентом и каждой нашей площадкой, доступной для него. Вычисляем ближайшую не по расстоянию, а по длине сетевого маршрута.

3aeffd735317a3f423b380e3bb7ac7af.jpeg

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

 Эта схема позволяет реализовать два режима кеширования:  

  1. Когда все видео, которые смотрят с какой-то площадки, раздаём с неё — это удобно некоторым провайдерам, которые хотят, чтобы весь трафик шёл через серверы на их площадке.

  2. Когда по IP-адресам пользователей собираем на площадке топ популярных видео именно для неё, с учётом мощности серверов и объёма канала. 

Так мы экономим канал от площадок до центрального дата-центра в Москве и повышаем эффективность кеширования. Например, есть площадки, для которых соотношение трафика к клиентам (downlink) и трафика от площадки до дата-центра (uplink) равно 40:1. 

Несмотря на то что большинство проблем с качеством видео возникает на «последней миле», CDN позволяет до 1,5 раз сократить time-to-first-byte и в результате примерно на 20% повысить качество видео. 

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

Результаты от внедрения QUIC для доставки видео пока не такие впечатляющие. Но для пользователей с самыми сложными сетевыми условиями улучшение действительно есть: 90-й перцентиль по time to first byte и tyme to first frame снизился на 20–25% в зависимости от платформы и типа контента. В предельных случаях ускорение может достигать и нескольких раз. Для обычных ситуаций видим уменьшение количества фризов на 3% и ускорение по ttff и ttfb на проценты. Здесь нам ещё есть куда расти — когда получим удовлетворяющие нас результаты, обязательно расскажем подробности.  

Воспроизведение и просмотр: CAP-теорема для видео

Последний этап, на котором замыкается путь видео, снова связан с клиентом. От плеера зависит, насколько комфортным будет просмотр. Если точнее, 2,5 млрд ежедневных просмотров роликов на нашей платформе. 

Помним, что метрика пользовательского опыта зависит от битрейта, времени старта, количества буферизаций (событий stall) и других факторов. 

9037ed578895cac85d1e9ec8eaf7395f.jpeg

В CAP-теореме для видео три компонента, между которыми приходится балансировать: это качество, скорость старта и количество буферизаций. 

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

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

Адаптивный стриминг

Базово есть две стратегии: одна основана на предсказании пропускной способности, вторая — на размере буфера. 

6a64bdaa1fddd49b2bfe4294a8ab0e5e.jpeg

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

Поэтому на практике используется гибридная схема. 

d946b2b129bc043b2d3ebc47b792cf52.jpeg

Оценивается и размер буфера, чтобы не возник stall, и пропускная способность, чтобы определить максимальный битрейт, который можно передать.

HLS vs DASH

Плеер на клиенте получает манифест с информацией о доступных качествах, их битрейте и расположении соответствующих сегментов видео. Формат манифеста зависит от выбранного протокола адаптивного стриминга. Тут, конечно, есть конкурирующие варианты: HLS от Apple и DASH от Google. 

Манифест HLS состоит из двух уровней вложенности. Сначала указаны битрейты каждого из качеств. На схеме, например, для самого нижнего качества прописан битрейт 200 Кбит/с. Также указано, где брать сегменты в соответствующем качестве. На втором уровне для каждого разрешения прописаны сегменты и их длительность. Из-за этой вложенности на первом кадре возникает лишний RTT (запрос на сервер) и проигрывание стартует медленнее.

d5ca3b8e44d0d721b43c6029e8f97373.png

MPEG-DASH организован чуть проще: в нём есть манифест с качествами, а индекс просто прописан в начале файла.

f3e380a6c12833f0de4de929ed6b1b44.jpeg

То есть на запрос с выбором качества плеер сразу получает нужный сегмент. И значит, до first frame проходит на целый RTT меньше времени (это примерно 100–500 мс). Причём root-манифест можно отдавать заранее, чтобы ещё ускорить старт. 

dc95c64ad51b923f65c24315f57825a4.jpeg

В остальном сейчас технологии HLS и DASH сравнимы по возможностям. Но когда в 2014 году мы запускали 4К, то безальтернативно использовали DASH, так как в HLS поддержка 4К появилась только в 2017-м. DASH поддерживает больше кодеков, включая свободные VP8 и VP9, а HLS поддерживается большим количеством устройств. 

© Habrahabr.ru




HLS

MPEG-DASH

Кодек

H.264, H.265*

любой, например VP9

Транспорт или контейнер

mpeg2-ts, mp4 c 2016

mpeg2-ts, mp4, webm

4K

c 2017

+

Манифест

m3u8

mpd

RTT до данных

2

1