Команды разработки RUTUBE, PREMIER, Yappy объединяются под брендом RUTUBE TECH

Команда — главный актив любой компании, а наша сила — в опыте и синергии. Теперь команды разработки RUTUBE, PREMIER, Yappy объединяются под брендом RUTUBE TECH. Мы долго шли к этому моменту, это важный этап нашего развития.

Объединение наших tech-команд под брендом RUTUBE TECH — это стратегическое решение, которое выведет наши продукты и сервисы на качественно новый уровень. Мы верим, что смелые идеи — это двигатель личного роста. Поэтому мы создаём среду, где талант становится сильнее, воплощаясь в реальные проекты
отметил CEO RUTUBE TECH Данила Овчаров.

Это важный шаг на пути к построению передовой big-tech компании. Вместе с объединением команд разработки в RUTUBE TECH мы делаем оргструктуру более прозрачной и эффективной, внутри единого юр. лица упростятся ротации между проектами. Мы также переходим к общей матрице должностей и performance review. Cильная и организованная команда — необходимая составляющая нашего успеха
CTO RUTUBE TECH Дмитрий Егоров.

Мы уверены, что это начало новой главы в нашей общей истории.

Собственное файловое хранилище для 400 Пбайт видеоконтента

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

В этой статье расскажем, как устроено файловое хранилище RUTUBE с точки зрения SRE, как мы пришли к именно такой конфигурации и как она работает на наших объемах — сейчас это порядка 400 Пбайт или 2 млрд объектов.

Начнём с требований к хранилищу, которые учитывают специфику видеоконтента и архитектуру RUTUBE (кстати, подробнее о ней рассказывается в отдельной статье):
  • Надёжность — базовое требование к любому хранилищу.
  • Низкая стоимость хранения контента — имеет большое значение, когда речь идёт о таких объемах контента, как у нас.
  • Высокое быстродействие — так как обращение к хранилищу может внести существенный вклад в скорость отклика сервиса, а мы хотим, чтобы пользователь не ощущал задержек, когда выбирает просмотр интересного ему видеофайла.
  • Горизонтальная масштабируемость тоже очень важна на таком объеме хранения. Так как объемы заливаемого видео постоянно растут, нам нужно регулярно вводить в эксплуатацию новые серверы. Когда вы систематически запускаете по 200-250 серверов файлового хранилища за раз, нужно делать это так, чтобы это занимало минимальное количество времени и требовалось как можно меньше ручного труда инженеров.

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

RUTUBE — видеохостинг, а не банк. Мы не закладываем требование стопроцентной сохранности данных при любых катаклизмах, которое подразумевает обязательно три реплики данных. Мы минимизируем риски потери пользовательского видео, используем две реплики, делаем резервные копии и на практике имели возможность убедиться, что этого достаточно. Когда мы на 10 часов потеряли целиком дата-центр с хранилищем видео, ни один из дисков реплик не вышел из строя и никакие пользовательские данные не были утрачены. Несмотря на очень большие количества жёстких дисков и серверов, в среднем мы теряем примерно от 3 до 10 дисков в месяц, что совсем немного. Поэтому для нас держать три реплики не целесообразно с точки зрения стоимости владения — цена вырастет кардинально.

Серверы видеохранилища
Какие серверы мы используем для файлового хранилища, как балансируем стоимость хранения и производительность на уровне железа?

HDD vs SSD
Как только появились SSD диски, аналитики начали «хоронить» HDD. Первые успехи в массовом производстве и, как следствие, удешевление SSD давали ощущение, что пройдет несколько лет и жесткие диски вымрут, останутся только SSD. Однако мы все всё ещё в той ситуации, когда стоимость хранения на SSD в 10 и более раз превышает стоимость хранения на традиционных жёстких дисках. Развиваются не только SSD, но и в HDD внедряют новые технологии.



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



Мы отказались от RAID-массивов и любых СХД на серверах видеохранилища. Используем железо любого вендора, но предъявляем два важных требования:
  • возможность полной настройки, от BIOS и IPMI до установки ОС, с помощью утилит, таких как Redfish, для полностью автоматического ввода в эксплуатацию любого количества серверов;
  • плотность жестких дисков в сервере не менее 36, а по возможности больше.

Объясню на примере, какое значение на наших объемах имеет плотность дисков в сервере. Рассмотрим современный хороший сервер Supermicro, ёмкость которого 90 жестких дисков на 4 юнита.


Если использовать диски по 18 Тбайт, то ёмкость одного сервера будет 1,62 Пбайт.

Соответственно, в обычную стойку на 10 серверов войдет 16 Пбайт. Это почти в 2,5 раза большая плотность по сравнению с более старой конфигураций на 36 дисков, где максимально в одну стойку можно впихнуть 6,5 Пбайт.


Мы сейчас используем в основном диски на 18 Тбайт, но Seagate уже выпустил в продажу 36-терабайтные серверные диски. С ними в одну стойку уже можно уместить 32 Пбайта — то есть всё видеохранилище, накопленное RUTUBE к лету 2025-го, без учёта репликации можно уместить всего в 15 стоек! А раньше это было бы несколько машинных залов.

Почему мы здесь вообще считаем стойки? Во-первых, их аренда тоже стоит денег: средняя цена по рынку где-то 140 тысяч рублей в месяц. В нашем примере при хранении 16 Пбайт на серверах по 90 дисков вместо 36 экономия получится 210 тысяч рублей в месяц. Не столь заметно для большой компании, но это ещё не всё.

Во-вторых, давайте рассчитаем стоимость железа на примере тех же серверов Supermicro 12-го поколения. С одной стороны, сама платформа на 90 дисков почти в два раза дороже, с другой — требуется 10 серверов, а не 25 (для ориентира используем цены европейского поставщика, потому что в России логистические факторы вносят существенные коррективы).


Даже при более дорогой платформе разница на эту ёмкость составит 34% или 36755 €.

Ниже расчёт для полной комплектации серверов со всем железом на платформе одного поколения — здесь разница составляет 21% и больше 128870 €.


Серверное ПО
На серверах видеохранилища RUTUBE стоит:
  • Rocky Linux — дистрибутив, который появился как форк Red Hat Enterprise Linux и должен быть на 100% с ним совместимым.
  • Angie — nginx-совместимый форк, который имеет дополнительные плюшки, например, в виде возможности получения конфигурации сервера и статистики по API и большого набора уже собранных сторонних модулей.
  • Модуль Kaltura для адаптивного видеостриминга.
  • FileHeap — самописное ПО, о котором поговорим дальше.

Указанные характеристики позволяют нам не испытывать каких-либо проблем с производительностью на серверах видеохранилища. Пиковый трафик отдачи RUTUBE составляет примерно 7 Тбит/с, однако он распределяется по CDN (подробнее о CDN RUTUBE читайте в отдельной статье), а нагрузка по сети на один сервер весьма разумная.

Ниже пример графика скорости отдачи непосредственно из файлового хранилища, для наглядности с достаточно слабого старого сервера.


Нагрузка на процессор (старого сервера с однопроцессорной конфигурацией) в пике составляет 40%, обычно меньше.



FileHeap
RUTUBE создавался в 2006 году. Тогда ещё не существовало хороших общепринятых готовых решений для файлового хранилища, Amazon S3 и Ceph появились позже. Поэтому видеохранилище создавалось логичным и доступным тогда способом — с нуля самостоятельно, ориентируясь на основную задачу, то есть хранение видео для видеохостинга.


Наше ПО управления хранилищем называется FileHeap. Оно написано на Python, для хранения всех объектов используется RabbitMQ и PostgreSQL, для кеша — Redis. Это хранилище разработано специально для хранения видео, оптимизировано под него и ни для чего другого не используется.

Рассмотрим основные задачи FileHeap.
  • Управление хранилищем контента — стандартный необходимый набор админских функций: добавлять и удалять серверы, регулировать количество репликаций, добавлять и удалять пользователей и так далее.
  • Загрузка/удаление контента в хранилище. Основная функция для любого файлового хранилища — загрузка файлов и их удаление.
  • Получение сведений о контенте в хранилище — его хэш-суммы, даты и всей информации о файле, которая нам необходима.
  • Раздача контента клиентам. FileHeap на самом деле ничего не раздаёт пользователям, он лишь сообщает сервису балансировки, где находится видео, на каком сервере его необходимо найти: в основном видеохранилище или в реплике на CDN-серверах. На основании чего уже балансер генерирует манифест для потока и отдаёт его на клиент.
  • Актуализация storage — постоянный процесс поддержания необходимого количества активных актуальных реплик (напомним, у нас их две).
  • Валидация storage — постоянный процесс проверки на ошибки доступности жестких дисков непосредственно на сервере. Если что-то выходит из строя, FileHeap сразу же узнаёт об этом через RabbitMQ, автоматически запускается система создания активных реплик на других дисках или серверах.
  • Балансировка storage — процесс перемещения реплик по серверам хранения для равномерного распределения нагрузки на них. Обычно мы добавляем сервера большими пачками, например, по 200 новых за раз. Чтобы не влиять на производительность хранилища, переносим данные в фоновом режиме, когда нагрузка на существующие серверы минимальна. Так постепенно контент размазывается по серверам, что позволяет равномерно балансировать нагрузку между ними.
  • Check online storage — процесс проверки реплики на доступность. Сервер хранилища может даже быть жив, но потерять сетевую связность с CDN — мы это тут же увидим на мониторинге, а балансировщик будет создавать манифест с живыми серверами, чтобы пользователи ничего не заметили.

Ниже схема взаимодействия видеосервисов. В рамках этой статьи не будем углубляться во все элементы (напишите в комментариях, что стоит раскрыть подробнее в следующих материалах), здесь нас интересует хранилище, в том числе то, как видео в него попадает.



Как видео попадает в видеохранилище
Пользователь может залить видео практически в любом формате и любом качестве. Мы поддерживаем upload для: MP4, AVI, WMV, MOV, FLV, MPEG-1, MPEG-2, MPEG-4, MPG, MPEGPS, 3GPP, WebM, DNxHR, ProRes, CineForm, HEVC (H.265). Загруженное видео нам нужно преобразовать в формат, который мы потом сможем показать на всём многообразии пользовательских устройств. Соответственно, перед тем как положить видео в основное видеохранилище, нужно его перекодировать (у нас основной кодек H.264) и нарезать в разные качества для адаптивного стриминга (поддерживаем от 144p до 8К).

Разберём этот процесс по шагам.


  • Данные от пользователя загружаются на upload-серверы, которые представляют из себя, по сути дела, просто серверы временного хранения, но с очень быстрыми NVMe-дисками. Их не очень много и их основная цель — максимально быстро получить контент от пользователя и начать обработку.
  • Как только видео заливается на upload, оно отдаётся на сервер транскодирования, который у нас называется WatchDuck.
  • Каждое видео нарезается во все поддерживаемые качества (ниже исходного) и в нужном кодеке отправляется в FileHeap.
  • FileHeap раскладывает все экземпляры видео во всех качествах по двум серверам видеохранения обязательно в двух разных дата-центрах.

Особенности хранения очень большого количества файлов
Как мы видим, видео хранится во многих качествах, то есть 400 млн единиц контента превращается примерно в 2 миллиарда объектов хранилища. Это может стать проблемой, если не учесть одну особенность устройства файловых систем, про которую нередко забывают в современной разработке. Возможно, потому что люди всё реже работают на низком уровне, а всё чаще оперируют абстракциями типа контейнеров.

Представьте: проект тестировали на dev, всё было хорошо, всё работало быстро. Отдали на прод, и через какое-то время производительность очень деградировала или и вовсе проект перестал работать. Что случилось?

Дело в том, что для хранения всех, скажем, пользовательских картинок разработчикам выдали один бакет. Однако в большинстве случаев, в частности в случае популярной реализации S3 MinIO, бакет — это просто отдельная папка в файловой системе (больше о работе с MinIO читайте в другой статье из нашего блога).


На 10-20 тысяч файлов — а dev за эти рамки обычно не выходит — всё замечательно работает. Далее проект выходит в продакшен, несколько недель нормально функционирует, бакет заполняется, и начинается резкая деградация скорости ответа MinIO. По достижении примерно 100 тысяч файлов (зависит от файловой системы на серверах) система полностью выходит из строя и уже не отдает ничего. Причем быстро это исправить проблематично.

Чтобы предотвратить подобное поведение, давно придумали хеш-структурированное хранение. Работает следующим образом: берётся, например, хеш-сумма файлов (мы вместо хеш-суммы используем UUID), создаются папки и подпапки по значениям последних символов хеш-суммы, файлы раскладываются в соответствующие подпапки — ни одна директория не переполняется.


Глубина вложенности может быть 2 или 3, при этом используется 4 или 6 последних символов хеш-сумм (или UUID, как в нашем случае). При вложенности 2 получается, что будет создано (16*16) ² = 65536 поддиректорий. При вложенности 3 получится уже ≈16 млн поддиректорий.

Для наглядности рассчитаем подходящую глубину вложенности в случае видеохранилища RUTUBE. На диски по 18/36 Тбайт, которые мы используем, помещается порядка 100 000 файлов — видео тяжелые и в среднем занимают несколько сотен мегабайт. При глубине вложенности 2 получится по 5-10 файлов в директории — это нам подходит. Если сделать глубину вложенности 3, то можно разложить 1 млрд файлов (примерно по 60 файлов в каждой директории). Таким образом можно в тот же самый бакет заливать сколько угодно файлов, просто регулируя глубину вложенности по папкам.

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

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


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

Существует два основных протокола адаптивного видеостриминга: HLS (HTTP Live Streaming, разработан Apple в 2009) и DASH (Dynamic Adaptive Streaming over HTTP, разработан рабочей группой MPEG в 2011 году). Они отличаются способами организации манифеста, но базово устроены похоже и вы точно сталкивались с их работой. Именно они отвечают за то, чтобы, если у пользователя ухудшилось качество связи, воспроизведение не прервалось, а просто уменьшить разрешение видео.

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

Чтобы на лету нарезать нужные фрагменты, мы используем nginx-модуль vod от компании Kaltura. Он читает исходный mp4-файл и динамически его сегментирует в нужный протокол: HLS (.m3u8 + .ts) или DASH (.mpd + .mp4).

Ниже короткие примеры конфигурации:
location /hls-vod/ {
    alias /media/;
    vod hls;
    vod_bootstrap_segment_durations 2000;
    vod_bootstrap_segment_durations 2000;
    vod_segment_duration 4000;
    vod_base_url "$video_id.mp4/";
    vod_mode local;
    hls_metadata_cache 16m;
    vod_align_segments_to_key_frames   on;
    vod_hls_segment_file_name_prefix   "segment";
    vod_manifest_segment_durations_mode accurate;
}
location /dash-vod/ {
    alias /media/;
    vod dash;
    vod_bootstrap_segment_durations 2000;
    vod_bootstrap_segment_durations 2000;
    vod_segment_duration 4000;
    vod_align_segments_to_key_frames on;
    vod_manifest_duration_policy min;
    vod_dash_manifest_format segmenttemplate;
    vod_dash_profiles urn:mpeg:dash:profile isoff-live:2011;
    vod_base_url "$video_id.mp4/";
}

Здесь созданы две локации, где в качестве root мы указываем одну и ту же папку с одними и теми же видеофайлами. При обращении к одной пользователь будет получать манифест DASH, к другой — HLS. Из основных параметров — длина чанков, и для разных форматов стриминга она может быть задана по-разному.

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

Пример запроса от плеера за HLS:

/hls-vod/0x5000c500c32ab248/77/ec/a8ae0fb363484dc180705b8a5dbc77ec.mp4/index.m3u8

Пример запроса от плеера за DASH:

/dash-vod/0x5000c500c32ab248/77/ec/a8ae0fb363484dc180705b8a5dbc77ec.mp4/manifest.mpd

А ещё vod-модуль позволяет на лету генерировать превью (thumbnails) — то есть картинку из видеофайла как стоп-кадр по временной метке в миллисекундах. Зачем это нужно? Во-первых, для перемотки по таймлайну, чтобы пользователь на миниатюрах видел, куда перетаскивает курсор. Во-вторых, для создания обложек. Авторы, которые заливают видео на RUTUBE, могут загрузить свою обложку, а могут использовать любой стоп-кадр, который и будет показываться на главной странице.

Надо заметить, что подход переупаковки на лету, кроме того что помогает экономить место в хранилище и обеспечивает скорость доступа к видео, еще и не вычислительно затратный. Единственную нагрузку создаёт генерация превью, нарезка чанков фактически не использует CPU, потому что это просто сегментирование MP4, никакой сложной обработки видео для этого не требуется.

Выше на графике скорость раздачи со всех вместе взятых серверов файлового хранилища. Пик нагрузки составляет ≈525 Гбит/с при общем трафике нашей платформы около 7Тбит/с. Это значит, что большая часть раздачи происходит с CDN-серверов, из хранилища забирается только незакешированое по CDN видео.

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


Также для экспериментов и резервного копирования мы используем S3 у разных партнеров. Но, как показала практика, производительность S3 в холодной конфигурации оставляет желать лучшего. Мало у кого из партнеров её в принципе достаточно для того, чтобы раздавать видео. В некоторых случаях, максимум, на что можно рассчитывать, это положить бэкап и забыть. Всё остальное — непозволительная роскошь, использовать что-либо кроме холодной конфигурации слишком дорого. Поэтому мы и остановились на использование собственных обычных серверов без СХД и RAID-массивов.

Итоги
Спроектированная еще в 2006 году система хранения видео RUTUBE, конечно, многократно дорабатывалась, в неё добавлялись новые функциональные элементы, но на уровне базовой архитектуры она сохранила свою простоту, которая сейчас позволяет нам легко масштабироваться под любые нагрузки.

Подход, описанный в этой статье, обеспечивает:
  • Производительность, которая позволяет обрабатывать миллионы запросов без деградации скорости.
  • Отказоустойчивость — данные дублируются на уровне целых серверов и дата-центров, а не отдельных дисков. Отказ целого дата-центра не приводит к потере данных.
  • Масштабируемость — новые серверы и диски легко конфигурируются и автоматически раскатываются по системе управляющей хранилищем, что позволяет на лету перестраивать топологию и гибко масштабироваться под растущие нагрузки.
  • Гибкость и полный контроль — можно настраивать репликацию под конкретные требования и ситуацию.
  • Оптимизацию стоимости хранения, благодаря контролю всех слоёв.

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

Как устроен CDN RUTUBE: железо, сеть, ПО

Меня зовут Дмитрий Иванов, я начальник отдела эксплуатации IT-инфраструктуры RUTUBE, что на наши деньги переводится как SRE-тимлид. В этой статье разберу задачу доставки контента и расскажу о решениях, которые помогают нам в RUTUBE.

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

Требуется: показывать всем нашим пользователям видео из библиотеки быстро, надежно и эффективно.

Как взаимосвязаны эти приоритеты и в чём проблема:
  • Раздавать видео по всей нашей большой стране и за её пределы из одного хранилища, очевидно, не быстро — пинг от Москвы до Владивостока около 100 мс.
  • Некоторые видео популярнее других, то есть одновременно их хотят посмотреть очень много пользователей. Если показывать такие видео напрямую из видеохранилища, это не будет надежно — потому что вся нагрузка пойдет на один сервер, серверу может стать плохо и «кина не будет».
  • Чтобы раздавать контент быстро, надо его разместить как можно ближе к зрителю. Но с учётом размера нашей библиотеки мы не можем её всю разложить по всем точкам присутствия пользователей — это будет неэффективно.

Решением этой задачи, как понятно из названия, является CDN — Content Delivery Network. Далее в статье сначала определим особенности нашего контента и то, какие требования к CDN в связи с этим возникают, а потом будем искать способы им соответствовать.

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


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



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

Два уровня кэширования
Для эффективного и быстрого доступа к горячему и холодному контенту соответственно выделим в CDN два вида кэша: L1 для холодного и L2 для горячего.


Исходный контент находится в видеохранилище. Далее разместим L1-кэш — уровень, который предназначен для холодного контента, ближе к хранилищу и с прямым доступом к нему. А L2, то есть горячий кэш, расположим как можно ближе к зрителям, в том числе в регионах. При этом, как показано на схеме, у региональных CDN-серверов с горячим контентом нет доступа в основное видеохранилище, вместо этого используется L1 для подкачки на уровень L2.

Тут можно было бы прокинуть VPN с L2 сразу в хранилище или сделать отдельный канал, но это была бы более сложная и дорогая схема. Каждая стрелочка на схеме не бесплатная с точки зрения ресурсов, перемещая контент как можно ближе к зрителю, мы экономим сетевой трафик.

Ниже в таблице характеристики серверов для раздачи горячего и холодного контента. Для горячего L2-кэша в среднем не требуются очень производительные серверы и скорости отдачи в 20-40 ГБит/с обычно достаточно, зато их нужно много. L1 же прокачивает через себя больше контента, так как является промежуточным звеном и обеспечивает доступ к тому самому длинному хвосту из миллионов видео. Поэтому холодные серверы обычно мощнее и оснащены сетевыми картами на 100 или 200 Гбит/с.

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



Как раздать 200 Гбит/с с одного сервера
Если просто взять сервер, вставить в него сетевую карту на 200 Гбит/с, то, к сожалению, без дополнительных усилий скорость отдачи будет намного ниже. Чтобы утилизировать всю пропускную способность сетевой карты, нужно знать, что такое NUMA — Non-Unified Memory Access.

Идея состоит в следующем: когда на сервере несколько процессоров, то скорость их доступа к разным областям памяти отличается. Потому что часть RAM для процессора будет локальной и соответственно более быстрой, а к другой он будет обращаться через шину (это называется interconnect), то есть медленнее. Ниже иллюстрация принципа работы NUMA.


Схема работы с памятью на многопроцессорных серверах
Для того, чтобы раздавать с одного сервера все 200 Гбит/с, нужно привязывать прерывание сетевых карт к ядрам того процессора, который их обрабатывает, чтобы не обращаться к памяти через шину.

К счастью, для сетевых карт Mellanox, которые мы используем, уже есть специальные скрипты, которые позволяют настроить NUMA (см. github.com/Mellanox/mlnx-tools). Скрипты имеют возможность выбора профиля: minimum latency предназначен для оптимизации задержек, а high throughput — для максимальной пропускной способности. Нас в данном случае интересует максимальная пропускная способность.

Кэширование
Разберём, как разложить контент по кэширующим серверам. Теоретически можно, например, с помощью rsync копировать видео из хранилища. Это даже будет работать, но придется городить целую схему, чтобы обеспечить эффективность и надёжность. Поэтому у нас кэширование организовано в обратную сторону: вместо того чтобы нам закачивать на CDN-серверы какие-то файлы, CDN сам скачивает нужные данные из хранилища по мере надобности при помощи обратного проксирования.

Мы используем nginx proxy_pass для скачивания и, что логично, делаем и proxy_cache, чтобы сервер складывал то, что скачал, в свой кэш. Также мы разделяем контент на чанки по 4 секунды, то есть скачиваются не сразу гигабайтные видеоролики, а чанки в несколько мегабайт.

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

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

Распределенное кэширование
На CDN-серверы под кэш мы ставим обычно 8-32 диска, но не объединяем их в общий RAID. Потому что, если вдруг RAID развалится, то потребуется долгая процедура rebuild. Вместо этого можно использовать такой трюк:
proxy_cache_path /media/d0 keys_zone=d0:512m levels=2:2:1 use_temp_path=off;
proxy_cache_path /media/d1 keys_zone=d1:512m levels=2:2:1 use_temp_path=off;
proxy_cache_path /media/d2 keys_zone=d2:512m levels=2:2:1 use_temp_path=off;
proxy_cache_path /media/d3 keys_zone=d3:512m levels=2:2:1 use_temp_path=off;
proxy_cache_path /media/d4 keys_zone=d4:512m levels=2:2:1 use_temp_path=off;
proxy_cache_path /media/d5 keys_zone=d5:512m levels=2:2:1 use_temp_path=off;

split_clients $request_uri $disk_cache {
  16.66%  d0;
  16.66%  d1;
  16.66%  d2;
  16.66%  d3;
  16.66%  d4;
  16.66%  d5;
  *   d0;
}


Здесь на каждый диск, который есть в сервере, определяется своя зона кэширования и через директиву split_clients разделяются запросы, которые приходят за контентом в кэш (подробнее см. документацию). Таким образом мы равномерно размазываем весь контент по всем дискам сервера.

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

Кроме того, нужно учесть подключение серверов к операторам связи. Чтобы не дублировать контент на одной площадке, то есть не хранить одни и те же видео на серверах, стоящих в одном CDN-узле, но подключенных к разным операторам, у нас организовано распределенное кэширование.



Распределенное кэширование устроено так, что каждый запрос, попадающий в nginx, проходит две стадии:
  • балансировка с consistent-hash,
  • непосредственно кэширование.

Таким образом, даже если запросы приходят от разных серверов, они попадают всегда на один и тот же кэш-сервер и дублирование не происходит. Сплошное пространство кэширования помогает эффективнее использовать ресурсы и обеспечивать большой объем закэшированного контента. Например, на площадке в Москве мы рассчитываем получить 10 Пбайт кэша.

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

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

Для выбора ближайшего сервера существует BGP Anycast.


По Anycast один и тот же IP-адрес анонсируется из разных мест. Когда запрос идет по такому адресу, он автоматически попадает на ближайший сервер с точки зрения топологии сети.

Сделать Anycast достаточно несложно, нужно:
  • купить сеть, которую мы будем анонсировать;
  • поставить на сервер демон маршрутизации, мы используем bird;
  • всё, profit.


Это будет работать, но если что-то в сломается, то починить будет трудно, потому что везде транслируется один и тот же IP-адрес, а значит, трудно локализовать проблему.

Кроме проблемы надёжности в нештатных ситуациях, с Anycast есть еще одна проблема: с точки зрения Anycast, ближайший сервер не всегда ближайший с точки зрения географии. Например, из Новосибирска ближайший сервер может оказаться в Санкт-Петербурге.

Чтобы определять ближайший к пользователю сервер с учётом физического расстояния, существует другая технология — GeoIP. GeoIP — это база данных производства компании MaxMind — по сути бинарный файл, который загружается в nginx-модуль. С его помощью в ответ на запрос с IP-адресом nginx возвращает: регион местоположения пользователя, город, а также, возможно, информацию об операторе.

Однако в GeoIP-базе MaxMind есть неточности, причём количество этих неточностей растет, поэтому нам приходится накладывать на неё правки.

Ниже представлен пример корректировки GeoIP-базы:
  • заводим список, где пишем IP-адреса и то, к какому региону их нужно относить;
  • через директиву geo формируем переменную, которая в ответ на IP-запрос возвращает расположение;
  • делаем map на приоритетное использование региона из нашего списка.
# geoip_corrections.conf example
198.51.100.0/24 Moscow; # RFC 5737 TEST-NET-2

# nginx.conf
geo $region_name_from_geo {
	# The variable will be empty if IP address does not match.
	include geoip_corrections.conf;
}

# Now we combine region names.
map $region_name_from_geo $region_name {
	# If there is no correction.
	''  	$geoip2_region_name;
	# And if there is.
	default $region_name_from_geo;
}


Это было бы не такой уж большой проблемой, если бы не влияло на пользователей. Но, к сожалению, о необходимости поправок мы обычно узнаём из обращений зрителей. Как это происходит? Неправильный GeoIP приводит к двум нежелательным ситуациям:
  • Если определить неправильный регион, то можно направить зрителя не на ближайший сервер. Зритель скорее всего этого не поймёт и не будет жаловаться, но мы же хотели так не делать.
  • Если неверно определить страну, то из-за локальных лицензионных ограничений контент может вовсе стать недоступен для пользователя. Тогда, возможно, он обратится в поддержку, мы всё исправим, но зритель на какое-то время останется без любимого шоу и будет расстроен.

Есть другой вариант GeoIP-базы, но с ними тоже есть свои особенности. Во-первых, в базе MaxMind 32 млн записей, а в geoip.noc.gov.ru — 4,5 млн записей. Допустим, это не так страшно, потому что это записи о сетях и они могут быть разного размера. Во-вторых, в базах различаются названия регионов, например, Chuvashia вместо Chuvash Republic. И третье, что нам действительно мешает перейти на эту базу: порядка 5 млн IP-адресов со всей страны в ней приписаны к Москве. То есть она опять не позволит всегда корректно определять ближайшие кэш-серверы, некоторым зрителям из регионов по-прежнему придется ждать лишнее время, чтобы посмотреть видео на RUTUBE.

Балансировка
Все запросы зрителей за видео идут не напрямую к одному из CDN-серверов, с сначала попадают в наше самописное ПО, которое называется видеобалансер.

Видеобалансер:
  • определяет, где находится зритель, по GeoIP-базе;
  • учитывает оператора, чтобы раздавать контент по возможности минуя меж-операторские стыки;
  • считает температуру видео, то есть горячий это контент или холодный;
  • мониторит нагрузку на серверы CDN;
  • распределяет зрителей на ближайший свободный сервер, где есть нужный контент.

Ниже скриншот из видеобалансера — у него утилитарный инженерный интерфейс, не самый красивый, но рабочий.


На скриншоте каждому серверу соответствует три строки, потому что балансер развернут в нескольких ЦОДах для отказоустойчивости. Цветами обозначен уровень загрузки: красному серверу уже хватит, жёлтый ещё может выдержать нагрузку, а зеленый явно недогружен.

Итоговая схема раздачи приведена на схеме ниже.


Когда пользователь открывает плеер RUTUBE происходит следующее:
  • клиент отправляет запрос за видео в видеобалансер;
  • балансер по GeoIP определяет ближайший к пользователю CDN;
  • балансер знает температуру запрашиваемого видео, он мониторит CDN-серверы и в соответствие с этими данными возвращает мастер-манифест на клиент со ссылками на плейлисты с чанками запрашиваемого видео;
  • по манифесту зритель уже направляется на конкретные CDN-серверы (с учётом всех уровней кэширования, которые мы рассмотрели ранее).

Edgestat на схеме выше — это наш сервис мониторинга, с помощью которого балансер узнаёт о состоянии серверов. Edgestat написан на Go и напрямую из псевдо-файловой системы /proc собирает параметры производительности процессора, сети и пр. Ниже пример файла, который модуль мониторинга возвращает в балансер:
{
  "net": {
	"tx_bytes": 3070389798640361
  },
  
  "cpu": {
	"user": 821038789,
	"nice": 7206904,
	"system": 1068090496,
	"idle": 8891017069,
	"iowait": 140402173,
	"irq": 183963736,
	"softirq": 1899188205,
	"steal": 0,
	"guest": 0,
	"guest_nice": 0
  },
  
  "tcp": {
	"out": 4009339463073,
	"retrans": 107337952956
  },
  
  "pressure": {
	"cpu": 0.42,
	"io": 1.77,
	"memory": 0.77,
	"irq": 1.7
  }
}


Разберем подробнее блок «pressure». Pressure Stall Information — подсистема внутри Linux-ядра, которая отслеживает задержки в работе системы, связанные с нехваткой железных ресурсов, таких как CPU, устройств ввода-выводы, память.

По меркам ядра PSI появилась относительно недавно, около 7 лет назад. А также буквально пару лет назад — совсем новинка — в неё добавили отслеживание задержек по обработке прерываний — IRQ (значения в микросекундах).

Мониторить irq особенно полезно на серверах, обрабатывающих много трафика, так как в таких условиях обработка прерываний от сетевой карты уже может вносить существенный вклад в общую производительность.
$ ls /proc/pressure
cpu  io  irq  memory
$ cat /proc/pressure/io
some avg10=2.50 avg60=2.38 avg300=2.34 total=13968383315
full avg10=2.35 avg60=2.22 avg300=2.15 total=12888830571
$ cat /proc/pressure/irq
full avg10=0.64 avg60=0.36 avg300=0.24 total=7294258624
$


На серверах, прокачивающих большой трафик, например, как у нас в Тбит/с, показатель irq pressure часто скачет и сообщает нам, что сервер перегружен, даже если этого не видно по другим характеристикам. Внедрение PSI помогло нам окончательно избавить CDN от тормозов — повысить скорость.

Для обеспечения дополнительной надёжности в схеме раздачи в мастер-манифесте содержится не один, а два CDN-сервера: основной и резервный. Мастер-манифест — это по сути плейлист из плейлистов, выглядит примерно так:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=478000, FRAME-RATE=25, CODECS="avc1.42c01f, mp4a.40.2", RESOLUTION=256x144
https://cdn-server
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=478000, FRAME-RATE=25, CODECS="avc1.42c01f, mp4a.40.2", RESOLUTION=256x144
https://backup-cdn


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

Сеть
Работа с сетью — также неотъемлемая часть эффективной реализации CDN, ведь на таких расстояниях и объемах трафика сеть легко может стать узким местом.

Ниже неполный вывод команда ip, который показывает список сетевых интерфейсов одного из наших CDN-серверов.
$ ip -c a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
	link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
	inet 127.0.0.1/8 scope host lo
   	valid_lft forever preferred_lft forever
2: aggr0: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:x1 brd ff:ff:ff:ff:ff:ff
3: aggr1: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:x2 brd ff:ff:ff:ff:ff:ff
4: aggr2: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond1 state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:x3 brd ff:ff:ff:ff:ff:ff
5: aggr3: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond1 state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:x4 brd ff:ff:ff:ff:ff:ff
6: anycast2: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
	link/ether xx:xx:xx:xx:xx:xa brd ff:ff:ff:ff:ff:ff
	inet 198.51.100.79/24 brd 89.248.230.255 scope global anycast2
   	valid_lft forever preferred_lft forever
7: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:xb brd ff:ff:ff:ff:ff:ff
	inet 192.0.2.1/24 brd 192.0.2.0 scope global bond0
   	valid_lft forever preferred_lft forever
8: bond1: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
	link/ether xx:xx:xx:xx:xx:xc brd ff:ff:ff:ff:ff:ff
	inet 203.0.113.2/24 brd 203.0.113.0 scope global bond1
   	valid_lft forever preferred_lft forever
$


То есть на каждом из десятков CDN стоят серверы с десятками же сетевых интерфейсов — всем этим нужно эффективно и надёжно управлять. Например, везде должны быть правильные согласованные с операторами настройки. Использовать для этого штатный NetworkManager не очень удобно, поэтому мы перешли на systemd-networkd.

systemd-networkd — это демон для настройки сети. Как и всё в systemd, все настройки в нём хранятся в текстовых файлах, что удобно для автоматизации, например, Ansible.

Ниже пример файла .link, который настраивает физические сетевые устройства. В нём задаётся максимальный размер буферов для эффективной раздачи больших объемов трафика.
# /etc/systemd/network/10-aggr0.link

[Match]
MACAddress=xx:xx:xx:xx:xx:xx

[Link]
Name=aggr0
RxBufferSize=max
TxBufferSize=max

В файле .netdev описываются виртуальные сетевые устройства, например, bond — объединение двух физических сетевых устройств в одно логическое для большей отказоустойчивости или скорости отдачи.
# /etc/systemd/networkd/bond0.netdev
[NetDev]
Name=bond0
Kind=bond

[Bond]
Mode=802.3ad
MIIMonitorSec=100ms
TransmitHashPolicy=layer3+4

Другой пример полезной настройки в .netdev — dummy-интерфейс. По сути это loopback, который мы используем для того, чтобы на него назначать Anycast-адрес. Можно назначить этот Anycast-адрес как второй ip-адрес на сетевой интерфейс, но тогда, если сетевой интерфейс перестанет работать, то и Anycast-адрес перестанет быть доступным.

# /etc/systemd/network/anycast2.netdev

[NetDev]
Name=anycast2
Kind=dummy


Третий вид файлов systemd-networkd это .network. Они описывают стандартные настройки: IP-адреса, gateway, маршруты и т.д.

# /etc/systemd/network/aggr0.network
[Match]
Name=aggr0
[Network]
Bond=bond0

# /etc/systemd/network/bond0.network
[Match]
Name=bond0

[Network]
Address=12.34.56.78/28
Gateway=12.34.56.79


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


Проблема в том, что при подключении двух операторов к одному серверу «в лоб» получается асимметричная маршрутизация. Её эффект показан на иллюстрации слева:
  • на anycast-адрес второго оператора приходит запрос,
  • ответ на этот запрос направляется default gateway, который скорее всего будет указывать в первого оператора.

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

Как сделать, чтобы ответ на запрос уходил тому же оператору, от которого он пришел? При помощи fwmark — меток сетевых пакетов. Это виртуальные метки, которые ставятся на сетевые пакеты и при этом существуют в рамках одного Linux-хоста. Они позволяют сделать такой трюк:
chain prerouting {
	type filter hook prerouting priority mangle; policy accept;
	iifname "bond0" ip daddr 198.51.100.0/24 meta mark set 0x00000010 accept comment "isp1 fwmark"
	iifname "bond1" ip daddr 198.51.100.0/24 meta mark set 0x00000020 accept comment "isp2 fwmark"
}


Выше представлены правила nftables: на запросы, приходящие через сетевой интерфейс «bond0», ставим на него метку 0x00000010 (неважно какую, важно, что не ноль), а на «bond1» ставим другую метку.

В соответствие с этим прописываем и исходящие правила маршрутизации:
$ ip rule
0:  	from all lookup local
110:	from 198.51.100.0/24 fwmark 0x10 lookup 100 proto static
120:	from 198.51.100.0/24 fwmark 0x20 lookup 101 proto static
32766:  from all lookup main
32767:  from all lookup default
$


Здесь в приоритете 110 написано: если запрос с Anycast-адреса и есть метка 0x10, то нужно посмотреть в таблицу номер 100, где будет default gateway для bond0; а если метка другая — то надо смотреть в другую таблицу, где уже будет default gateway для bond1.

Воедино входящие правила фаервола и исходящие правила маршрутизации связывают несколько sysctl:
net.ipv4.tcp_fwmark_accept=1
net.ipv4.fwmark_reflect=1
net.ipv4.conf.all.src_valid_mark=1


Здесь написано следующее: если на сетевой пакет, который пришел на данный сетевой интерфейс, есть метка, то её нужно скопировать на весь сокет и выставлять на все исходящие пакеты в рамках соединения.

Player events
Мы мониторим состояние серверов, но кроме того, для надёжности, плеер пользователя в случае каких-либо проблем научен отправлять специальные сообщения, которые называются player events. Если на клиенте, в вебе, в мобильном или Smart TV приложении RUTUBE возникнут какие-то проблемы с доступом к CDN, то мы узнаем об это по резервному маршруту. Например, сбои в каком-то сегменте сети, дадут всплеску player events и наш мониторинг тут же отреагирует.

И последняя в этой статье оптимизация: простая, но важная. Мы уже говорили, что используем демон маршрутизации BIRD, чтобы анонсировать Anycast. Логично, что тогда должен быть запущен и nginx, чтобы он что-то раздавал. Если запустить bird, но не запустить nginx (а у нас такое бывало), то зрители придут и попадут в черную дыру. Чтобы такого избежать, можно использовать такой трюк:
# /etc/systemd/system/bird.service.d/requisite_nginx.conf
[Unit]
# If nginx is stopped, bird will be stopped as well.
# If nginx is not running, bird will refuse to start.
# If bird is stopped, nginx is not affected.
# If nginx is restarted, bird is not affected.
Requisite=nginx.service


Главное тут в последней строчке: если nginx запущен, то bird работает; если nginx выключить, то bird погаснет; если nginx не запущен, то и bird не запустится.

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

Вот три основных момента, на которые нужно обратить внимание, если вы строите свой CDN:
  • Если вы только начинаете строить CDN, то начните с BGP Anycast как наиболее простого варианта. Но не ограничивайтесь им и подключайте узконаправленные средства балансировки, подходящие для вашего профиля трафика и нагрузки.
  • Используйте разные источники мониторинга: и изнутри системы, и снаружи.
  • Pressure Stall Information — это ваш союзник в борьбе с тормозами.

Архитектура национального видеохостинга: путь RUTUBE к 10 Тбит/с с использованием своей CDN

За полгода с июля 2024 года большинство аудиторных и технических показателей RUTUBE выросло в разы: количество ежедневных пользователей выросло почти в 4 раза; количество видео, ежедневно загружаемых на видеохостинг — в 3 раза, с 330 тыс. до 1 млн единиц контента; CDN-трафик — в 4 раза и в пиковые часы превышает 7 Тбит/с. Как архитектура сервиса показала себя в условиях продолжительного «нагрузочного тестирования» и как команда переживала такой рост нагрузки, читайте в этой статье.



Меня зовут Эльдар Ниязов, я директор департамента развития и эксплуатации ИТ-инфраструктуры RUTUBE. В статье разберу верхнеуровневое устройство основных компонентов видеохостинга: раздачу видео и CDN, загрузку на платформу, хранение, воспроизведение и прямые трансляции. А в следующих статьях этого блога мы с коллегами рассмотрим каждый элемент подробнее и копнём вглубь реализации.

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

Видеохостинг работает на вебе, Android, iOS, Smart TV. Поддерживает просмотр горизонтальных и вертикальных видео, прямые трансляции и вещание ТВ-каналов.

По данным Mediascope за декабрь 2024 г. сервис посетило 78,3 млн человек, а среднее количество ежедневных пользователей составляет 18 млн. RUTUBE смотрят по всей России: из городов миллионников и населённых пунктов поменьше (почти половина зрителей живут в городах с населением менее 100 тыс. чел.).


Объём видеохранилища на сегодня составляет более 250 Пбайт, в нём хранится около 400 млн видео и каждый день их количество увеличивается в среднем на 1 млн — столько новых видео пользователи в среднем загружают на платформу.

Чтобы обеспечить быстрый и надёжный доступ к контенту, наша собственная геораспределенная сеть доставки контента (CDN) состоит из 6 ЦОДов в Москве и одного в Санкт-Петербурге, 4000 серверов (из них 700 серверов для обработки видео), более 200 CDN-серверов, более 25 городов присутствия, страны СНГ и даже США. Ёмкость сети составляет более 10 Тбит/с.


Видеохостинг разрабатывает собственная, полностью in-house команда, которая так же как и ИТ-инфраструктура смогла гибко перестроиться и масштабироваться.

RUTUBE — это более 100 микросервисов. Кодовая база бэкенда написана преимущественно на одном из трёх языков: Python3 — 600 тыс. строк, Node.js — 600 тыс. строк, Golang — 300 тыс. строк. В инфраструктуре у нас высокий уровень автоматизации: IaC (Terraform, Ansible) составляет примерно 200 тыс. строк.


CDN (раздача)
В век клипового мышления нужно как можно быстрее доставлять контент пользователям. Чтобы минимизировать задержку, мы, во-первых, разнесли контент по CDN в разных городах, чтобы кешировать его ближе к пользователю. Во-вторых, разделили CDN на два уровня: горячий (более x запросов в сутки) и холодный. За видео, которое не было востребовано в течение долгого времени, например, целого месяца, мы обратимся к основному хранилищу.


Такое разделение позволило:
  • повысить скорость доставки контента до конечного пользователя;
  • сэкономить на хранилище и оптимизировать использование серверных ресурсов;
  • снизить затраты на передачу данных по сети.

Подходящий узел CDN мы можем определять по GeoIP (т.е. ближайший) или по ISP (Internet Service Provider). Наши CDN-серверы, естественно, тоже подключены к сети через провайдеров, и в некоторых случаях с точки зрения задержки выгоднее избежать лишних стыков между провайдерами, чем выбрать ближайший, но находящийся в другой сети CDN. В предельном случае грамотное использование CDN позволило нам снизить время доставки с 300 мс до 10 мс.

Стандартный сетап сервера CDN с холодным контентом: 512 Гбайт оперативной памяти, 100 Тбайт дисков под хранение и 2 диска под ОС, 2 сетевые карты — 100 Гбит/с на отдачу, 25 Гбит/с на подгрузку контента из основного хранилища.

Горячий CDN-сервер мощнее и в нём стоят одинаково быстрые сетевые карты на 100 Гбит/с на download и на upload.

График раздачи в течение типичной недели выглядит примерно так.


Зеленая линия — трафик с CDN первого уровня, раздача холодного контента, красная линия — трафик с CDN второго уровня, синяя линия — суммарный трафик

Воспроизведение видео
Рассмотрим, что происходит, когда пользователь запускает видео в плеере RUTUBE.
  • GET-запрос отправляется в балансировщик, который по GeoIP и ISP рассчитывает «расстояние» до CDN-серверов.
  • Балансировщик видео получает из нашего хранилища FileHeap адрес CDN, на котором есть видео, и адрес самого видео.
  • Отдает плееру М3U8-манифест c указанием основного и запасного CDN-узла и адрес исходного видео.
  • Плеер идёт за видеочанками сначала на CDN второго уровня. Если контент не популярный и его нет в горячем кеше, то плеер запрашивает видео с CDN первого уровня, если и там не оказалось — то идет в основное хранилище.


Загрузка видео
  • В среднем каждый день пользователи RUTUBE загружают на видеохостинг 1 млн новых видео. Загрузка видео — важный и нагруженный сервис и один из самых сложно масштабируемых. Расскажу, что происходит, когда пользователь в личном кабинете нажимает «+», «Загрузить видео».
  • Балансировщик загрузки отдаёт адрес сервера, на который отправляется загрузка (под загрузку у нас выделено более 800 серверов).
  • Наш собственный сервис Watchduck, который по нашей традиции назван в честь животного, нарезает видео на разные качества. Watchduck написан на Python3, умеет транскодировать видео и на GPU, и CPU, что нам очень пригодилось в момент бурного роста нагрузки и невозможности быстро увеличить парк видеокарт. Нарезкой разных качеств и обложек занимается ≈ 700 серверов.
  • После нарезки Watchduck идёт в FileHeap, под который отведено по 10 серверов в основных ЦОДах и который обеспечивает балансировку нагрузки на хранилище. FileHeap получает адрес, куда и в какое именно хранилище положить загрузку.
  • Естественно вся загрузка и нарезка происходит чанками — по 3–6 Мбайт.


Устройство видеохранилища. Альтернатива S3
Для хранения видео мы используем не стандартный S3, а собственное приложение. Наше решение существует давно, хорошо себя зарекомендовало и в своё время было быстрее, чем альтернативы, например, Ceph.

Главный минус S3 для нас — это необходимость в кеширующих серверах, причем в определённом соотношении с бакетами, чтобы не тормозило. А большое количество дополнительных серверов — это большие затраты на покупку и обслуживание оборудования. ​​


Кроме экономии на оборудовании собственная реализация хранилища даёт следующие плюсы:
  • возможность глубокого мониторинга на каждом этапе;
  • гибкая адаптация под свои нужды;
  • не надо платить за лицензии и поддержку;
  • скорость и производительность.

Мы используем партнёрские S3 в качестве резерва, арендуем мощности у крупных известных поставщиков. Однако максимальная скорость отдачи, которую нам могут обеспечить сторонние S3, составляет всего 60 Гбит/с. Иначе их сервисы деградируют и страдают другие клиенты.

Видеохранилище RUTUBE состоит по сути из трёх частей:
  • DS-origin — само хранилище, разнесенное по разным ЦОДам;
  • FileHeap — балансировщик;
  • CDN-серверы.

Оно устроено предельно просто, что помогает легко организовать любой мониторинг и при необходимости что-то подтюнить.

Что в результате? Ниже графики нагрузки в обычную неделю без происшествий и пиковой посещаемости, это скорость отдачи контента напрямую с основного хранилища DS-origin (т.е., когда контента не оказалось на CDN первого и второго уровня) и с использованием партнёрских S3.


Красная линия — график отдачи трафика с основного собственного хранилища RUTUBE, пиковая скорость в среднюю неделю составляет порядка 500 Гбит/с. Синия линия — отдача с партнерских S3, скорость составляет 35–60 Гбит/с
Прямые трансляции
Когда пользователь хочет провести прямой эфир через RUTUBE и создает трансляцию, под капотом сервиса происходит следующее:
  • видеопоток от пользователя поступает на RTMP-балансировщик;
  • RTMP-балансировщик распределяет поток в разные ЦОДы (основной и запасной);
  • далее поток попадает в сервис live-транскодирования на FFmpeg, где нарезается в разные разрешения — от 144 до 4к;
  • транскодирование также проходит через балансировщик, выполняется в разных ЦОДах и резервируется по двум ссылкам;
  • из балансировщика поток попадает на CDN, ближайший к зрителю трансляции.

Наши трансляции минимально отстают от реального времени — на 3–5 секунд.


Схема работы прямых трансляций RUTUBE. Genetta — собственный сервис, агент по управлению ffmpeg на live-транскодерах

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

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

Где потребовались дополнительные ресурсы при росте нагрузки:
  • Загрузка и обработка — первое, где требовалось масштабирование. Обработка видео, его нарезка во все качества — ресурсоемкий процесс, а когда авторы резко начинают заливать в видеохостинг все свои ролики, накопленные за годы творчества, это может стать потенциальной проблемой. Мы арендовали 1000 дополнительных серверов у партнёров, а сам процесс не потребовал изменений, просто у балансировщика появился больший пул серверов.
  • Хранение — новые видео надо где-то хранить. На всякий случай подстраховались арендными S3 и увеличили количество кеш-серверов.
  • Раздача и трансляции имеют больший запас прочности из-за особенностей архитектуры, поэтому тут удалось подстраховаться тем, что быстро купили несколько серверов в частном порядке и выиграли время на полноценную закупку.

Специфика видеохостинга в том, что нагрузки на запись гораздо меньше, чем нагрузки на чтение. Поэтому мы держим по одному мастеру в каждом ЦОДе и много реплик на чтение.


Итого
Основные элементы архитектуры RUTUBE, заложенные разработчиками сервиса ранее, позволили нам горизонтально масштабироваться при кратном росте нагрузки. Конечно, когда в течение августа 2024 г. трафик увеличился примерно в два раза, нам с командой пришлось попотеть: перераспределять имеющиеся ресурсы, сетапить новые, подключать арендные мощности, готовиться к сценариям плавной деградации и т.д. Для нас главное — команда быстро и чётко прошла критическую фазу масштабирования. Теперь мы можем в чуть более равномерном, но по-прежнему высоком темпе наращивать мощности: и железные, и человеческие. Потому что планы у нас амбициозные ;)

PUE 1,03

Регулируется автоматически с использованием данных из Prometheus, которые передаются в специально разработанное приложение Go, управляющее центробежными вентиляторами и заслонками воздухообработки, как в холодную погоду

Когда у нас сгорает диск - ставим 2 диска raid1 так уж и быть (Кемерово)



  • Поэтому постепенно старые серверы 2023 года заменяются новыми дисками в raid1
  • Если кто-то желает чтобы его мигрировали — пишите тикеты
  • Тем кому данные не важны просьба не отвлекать за зря
  • Касается — локации Кемерово

bill.yacolo.net/billmgr


От Ryzen до EPYC: как процессоры AMD обеспечивают работу современных игр



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

Взять, к примеру, движки Unreal Engine и Unity: последние несколько лет они предъявляют новые требования к оборудованию, особенно к тактовой частоте. Игры на Unreal Engine часто сильно зависят от производительности одного ядра, где скорость каждого ядра важнее, чем их общее количество. Хотя Unreal Engine 5 делает шаги к лучшему масштабированию многоядерных процессоров, более высокие тактовые частоты по-прежнему обеспечивают бесперебойную работу большинства современных игр.

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

Рост и оптимизация идут рука об руку, и для достижения этого баланса в современной игровой индустрии один процессор выделяется среди остальных…

Введите AMD
Компания AMD ворвалась на рынок игровых процессоров с Athlon 64 X2 в 2003 году и с тех пор продолжает разрабатывать процессоры для потребительского рынка.

Прошло двадцать лет, и теперь AMD Ryzen — имя, известное геймерам по всему миру (я до сих пор с гордостью ношу 5800x3d).

Итак, когда AMD анонсировала в 2022 году Ryzen 7950X — самый мощный на сегодняшний день процессор потребительского класса — он произвел фурор в отрасли. Будучи частью серии 7000, 7950X обладал 16 ядрами, высокой производительностью в однопоточном и многопоточном режимах и лучшими тактовыми частотами среди всех массовых процессоров на тот момент. Журнал PC Mag далее описал 7950X как «самый быстрый процессор, который можно купить, не перейдя на серверное оборудование».

Но на этот раз не только геймеры остались недовольны: предприятия также начали устанавливать 7950X в своих центрах обработки данных.

С успехом приходит спрос
AMD знала, что с серией 7000 они на верном пути. Но я уверен, что они не ожидали такого спроса на 7950X во всей игровой индустрии. Процессоры Zen3 EPYC — корпоративная серия AMD — уже существовали некоторое время, но разработки Ryzen в 2022 году быстро превзошли все процессоры, которые студии и хостинг-провайдеры использовали ранее. Очень быстро 7950X превратился из B2C-продукта в B2B-продукт.

Преимущества в игре очевидны: более высокая производительность потоков и более высокая тактовая частота позволяют поддерживать больше игроков на одном компьютере без ущерба для игрового процесса. Как я уже упоминал, прогресс в разработке игр — это всегда баланс между ростом и оптимизацией; мощь 7950X укрепляет игровую инфраструктуру, обеспечивая более плавный и захватывающий игровой процесс без дополнительных затрат. Выигрыш для всех.

Фактически, многие наши партнёры — от крупных разработчиков AAA-контента, которых мы поддерживаем напрямую, до компаний частного хостинга B2C и провайдеров управляемого хостинга B2B — уже используют процессоры Ryzen, снижая затраты и получая доступ к более мощным технологиям. Ведущие игровые студии знают, что создание современных игр требует важного сочетания мощных технологий и квалифицированных экспертов по их использованию.

Второй игрок готов
Ryzen 7950X завоевал сердца и умы как потребителей, так и предприятий. Три года спустя он даже возглавил список «Лучшие процессоры AMD 2025 года» по версии TechRadar.

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

В мае 2024 года AMD решила выпустить EPYC 4004 — новую линейку процессоров корпоративного класса, основанную на той же архитектуре Zen 4, что и серия Ryzen 7000. У AMD уже был рецепт успеха с 7950X, поэтому целью EPYC было предложить аналогичные процессоры, но предназначенные для предприятий, а не для потребителей: круглосуточную нагрузку на центры обработки данных, поддержку ECC (памяти с коррекцией ошибок) и зеркалирование памяти для повышения уровня резервирования.

Встречайте EPYC 4564P — флагманский процессор серии 4004, созданный для удовлетворения потребностей бизнеса в процессорах серии 7950X. И, как видите, их конфигурации практически идентичны:


Более того, процессоры EPYC также выигрывают от более низкой совокупной стоимости владения (TCO), поскольку серверы будут иметь корпоративные гарантии, меньше простоев и меньше замен.

Для разработчиков и хостинг-провайдеров взгляды на процессоры изменились. Чистая скорость важна, но не менее важно и то, как она сохраняется со временем, и именно здесь AMD EPYC 4564P блистает. Созданный на той же архитектуре Zen 4, что и Ryzen 7950X, он обеспечивает ту же однопоточную производительность, но оптимизирован для центра обработки данных благодаря функциям надежности, необходимым для непрерывных рабочих нагрузок: высокой степени параллелизма, бесперебойности работы и стабильности.

Чипы EPYC также обладают преимуществами Ryzen в области однопоточной производительности, так что по сути это тот же мощный процессор, просто созданный для сред, которые никогда не спят.

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

Что будет дальше?
За последние четыре года разработчики, издатели, сервисы управляемого хостинга и поставщики частных серверов B2C достигли больших успехов в оптимизации своих многопользовательских игр. Прогресс в разработке игр, похоже, идёт в ногу с развитием игровой инфраструктуры, на которой они размещены, и обсуждение Ryzen EPYC — яркое тому подтверждение.

В то время как AMD Ryzen 7950X продолжает обеспечивать исключительную производительность для геймеров, те, кто арендует серверы у поставщиков, использующих EPYC 4564P, могут рассчитывать на ту же мощность с дополнительными преимуществами корпоративной надежности и эффективности.

На сайте servers.com мы ежедневно наблюдаем эти изменения, работая с хостинг-провайдерами, которым важна стабильная производительность и доступность. Будучи геймером, я понимаю стремление к производительности; моя задача — обеспечить нашим клиентам необходимую производительность и поддержку благодаря инфраструктуре на базе EPYC для бесперебойной многопользовательской игры.

Я надеюсь, что со временем чип EPYC станет таким же популярным среди корпоративных пользователей, как 7950X среди потребителей.

Как сократить расходы на масштабирование Kubernetes



Расскажем, как сократить расходы на Kubernetes
Приглашаем на вебинар 13 ноября в 16:00. Расскажем, как снизить затраты на масштабирование Kubernetes при помощи Karpenter. Познакомим с решением и поделимся результатами, которые вы получите от взаимодействия с Karpenter. Будет полезно DevOps-инженерам, техлидам и СТО, а также системным администраторам и архитекторам.
selectel.ru/blog/events/karpenter-kubernetes/

Что будет
  • Обзор возможностей Karpenter и его сравнение с Cluster Autoscaler.
  • Воркшоп: как настроить Karpenter в кластерах Managed Kubernetes.
  • Кейсы применения Karpenter. Оптимизация GPU-инфраструктуры с Karpenter.
  • Ответы на вопросы.

Всё самое интересное за октябрь



Привет! Прошел месяц, и мы, как обычно, спешим поделиться с вами нашими новостями и событиями мира облачных технологий. В октябре главной темой стал ИИ — в общих трендах, публикациях и обновлениях GPU-платформы mClouds.

Прокачали облако mClouds для работы с нейросетями
Мы продолжаем обновлять нашу облачную инфраструктуру и адаптировать ее для работы с большими языковыми моделями:
  •  В нашей GPU-платформе видеокарты NVIDIA L40S 48GB теперь работают с последними драйверами от NVIDIA.  
  • Для некоторых сценариев получили ускорение до 10% на картах L40S в реальных ИИ-задачах.
mclouds.ru/pricing/gpu-for-ai-ml/

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


habr.com/ru/companies/mclouds/articles/958118/



Подготовились к зиме: новая коллекция мерча уже доступна
К наступлению холодов мы подготовили новую линейку мерча — надеемся, что с ним вам будет тепло
и уютно! Среди новинок — кружки, термосы, бафы, шоперы и ремувки.
Получить стильный и теплый мерч просто: будьте нашим клиентом! Раздаем мерч
в активностях и дарим просто так за вашу лояльность.
t.me/mclouds/916

Опубликовали статьи на Хабре
Кому нужны игровые видеокарты NVIDIA с 48 ГБ VRAM и почему их до сих пор нет

Топовые игровые видеокарты с 24 ГБ VRAM могут не справляться с тяжелыми задачами и уровнем графики — нужны видеокарты на 48 ГБ. Однако подобных потребительских карт на рынке пока нет. В статье разбираемся, что мешает запустить их в серию и стоит ли ждать их появления.
habr.com/ru/companies/mclouds/articles/957108/

Windows, которую мы помним: от 1.0 до 11 — история ОС, ставшей частью нашей жизни
В октябре 2025 года Windows прекратила поддержку одной из самых популярных ОС — Windows 10. Вспоминаем, какой путь прошла ОС и чем она запомнилась пользователям: от первого, практически провального релиза до ускоренного ИИ.
habr.com/ru/companies/mclouds/articles/955220/

24 000 чипов NVIDIA и 2600 Rhea1 в действии: как устроен самый мощный европейский суперкомпьютер JUPITER
В немецком исследовательском центре Юлиха начал работу JUPITER — первый европейский суперкомпьютер, способный выполнять квинтиллион (10^18) операций в секунду. Рассказываем, как устроен суперкомпьютер, сколько он стоит и какие задачи будет решать.
habr.com/ru/companies/mclouds/articles/952182/

Как загрузить GPU на максимум. Разбираем узкие места в инфраструктуре для ИИ
 Без быстрых дисков, продуманной внутриузловой топологии и высокоскоростной сети даже мощные GPU будут простаивать.
В статье разобрали, как спроектировать сбалансированную инфраструктуру.
habr.com/ru/companies/mclouds/articles/959872/

В октябре вышла новая статья 
Выбираем GPU для ИИ: Видеокарты NVIDIA RTX 4090 и 5090 vs L40S 48GB.

Она поможет подобрать наиболее подходящую видеокарту под ваши задачи.
В 2025 году всё больше компаний используют ИИ не только для решения IT-задач, но и в маркетинге, продажах, сервисном обслуживании. Именно поэтому мы
и дальше будем внедрять новинки в области ИИ и наращивать мощность нашей облачной инфраструктуры, чтобы оставаться надежным партнером для вас.
mclouds.ru/2025/10/nvidia-rtx-4090-5090-vs-l40s/

Серверы в наличии 196x США 352х ЕС