На конференции C++ Russia 2022 мы провели публичное System Design интервью с задачей спроектировать ленту видеохостинга — систему, похожую на YouTube. Этот кейс демонстрирует работу с асинхронной обработкой, транскодированием видео и построением персонализированных фидов.
Видеозапись интервью
Полная запись публичного интервью доступна на YouTube. Рекомендую посмотреть, чтобы увидеть итеративный процесс проектирования.
Смотреть на YouTubeПостановка задачи
Video Hosting Feed
Спроектировать приложение, которое позволяет создателям контента загружать видео, а зрителям — просматривать его в хронологической ленте с возможностью выбора качества.
Функциональные требования
Быстрая загрузка
Создатели могут быстро заливать видео
Уведомления
Видео появляется в лентах подписчиков по готовности
Выбор качества
Переключение от 360p до 1080p
Хронологическая лента
Простая сортировка по времени публикации
Нефункциональные требования
Оценка нагрузки (Back of the Envelope)
Ключевой вывод: Основная нагрузка — это хранение и доставка видео, а не количество запросов. Критически важны эффективное использование CDN и оптимизация хранилища.
Высокоуровневая архитектура
Система разделена на два основных пути: Write Path (загрузка и обработка видео) и Read Path (просмотр и лента).
Video Hosting: High-Level Map
ingestion + transcoding + feed + video deliveryIngestion + Processing Plane
Storage + Serving Plane
Контур upload/transcoding масштабируется независимо от read-serving. Это позволяет отдельно наращивать воркеры обработки и edge capacity CDN.
Read/Write Flow
Read/Write Path Explorer
Переключайте путь и прогоняйте шаги обработки в режиме Play.
Write Path: operational notes
- Клиент загружает оригинал в upload-контур, после чего API возвращает `video_id` и статус обработки.
- Видео разбивается на задачи транскодирования; воркеры генерируют несколько quality профилей.
- Готовые renditions и манифесты публикуются в origin storage, а metadata фиксируется в DB.
- После статуса `ready` запускается fan-out в feed storage и уведомления подписчикам.
Read Path: operational notes
- Viewer запрашивает feed, сервис возвращает список `video_id` по подпискам и персональным сигналам.
- Metadata API отдает playback manifest (HLS/DASH) и доступные разрешения.
- CDN обслуживает сегменты с edge-узлов; горячий контент почти всегда читается из cache.
- При cache miss edge запрашивает сегмент в origin storage и сразу прогревает локальный cache.
Ключевые компоненты
Upload API
Принимает бинарные файлы от создателей и сохраняет во временное хранилище.
POST /v1/videos → {video_id, upload_url}Message Queue (Task Broker)
RabbitMQ или аналог для управления задачами транскодирования. Родительская задача порождает 4 дочерние — по одной на каждое разрешение.
Video Workers
Stateless воркеры для транскодирования. Читают задачи из очереди, обрабатывают видео (FFmpeg), сохраняют результат в Blob Storage. Легко масштабируются горизонтально.
Blob Storage
S3-совместимое хранилище (MinIO, Ceph) для видеофайлов. Разделено на временное (для загрузки) и постоянное (обработанные видео).
Feed Database
Document-oriented NoSQL база (MongoDB, Cassandra) для хранения предрассчитанных лент. Шардируется по user_id. Лента — массив ID видео, отсортированный по времени.
CDN
Критически важен для доставки видео. Кеширует популярный контент на edge-серверах ближе к пользователям. Снижает нагрузку на Blob Storage и уменьшает latency.
Модели данных
Video Meta
{
"id": "uuid",
"author_id": "user_123",
"title": "My Video",
"description": "...",
"created_at": "2024-03-15T10:00:00Z",
"status": "ready",
"versions": {
"360p": "s3://videos/uuid/360p.mp4",
"480p": "s3://videos/uuid/480p.mp4",
"720p": "s3://videos/uuid/720p.mp4",
"1080p": "s3://videos/uuid/1080p.mp4"
}
}User Feed
{
"user_id": "user_456",
"feed": [
"video_id_1",
"video_id_2",
"video_id_3",
...
],
"last_updated": "2024-03-15T12:00:00Z"
}Предрассчитанная лента — массив ID видео от подписок, отсортированный по времени.
Стратегии построения ленты (Fan-out)
→Fan-out on Write (Push)
При публикации видео добавляем его во все ленты подписчиков.
←Fan-out on Read (Pull)
При запросе ленты собираем последние видео от всех подписок.
Гибридный подход
Для обычных авторов используем Push (fan-out on write). Для авторов с миллионами подписчиков — Pull при чтении. Это классический компромисс, который использует Twitter/X.
Инфраструктурные сервисы
Load Balancer L4/L7
Распределение трафика между API серверами
Service Discovery
Регистрация и обнаружение сервисов (Consul, etcd)
Auto-scaling
Автоматическое масштабирование воркеров по нагрузке
Monitoring
Метрики, алерты, логирование (Prometheus, Grafana)
Rate Limiting
Защита от abuse и DDoS
Circuit Breaker
Graceful degradation при сбоях
Ключевые выводы из интервью
Разделяйте Write и Read пути
Асинхронная обработка видео (Write) и синхронное чтение ленты (Read) имеют разные требования и масштабируются по-разному.
Используйте очереди для тяжёлых операций
Транскодирование — ресурсоёмкая операция. Message Queue позволяет управлять нагрузкой и легко масштабировать воркеры.
CDN — must have для медиаконтента
При 300 ТБ нового контента в день без CDN система не выживет. Кеширование на edge снижает нагрузку и latency.
Предрассчитывайте где возможно
Предрассчитанные ленты (feed) значительно быстрее, чем сборка на лету из множества источников при каждом запросе.
