Нефункциональные требования

  • 500 million DAU
  • Каждый пользователь 150 раз запрашивает ленту
  • Каждый пользователь 50 раз пишет посты в день
Расчеты

Просмотр ленты

  • 500M × 150 = 75 000 000 000 запросов
  • Средний Read RPS: 75B ÷ 86,400 сек = 868 056 RPS
  • Пиковый Read RPS: 868 056 × 3 = 2 604 167 RPS
    • 3 - примерное значение для peak multiplier. Главное не забудь проговорить про пиковые значения

Посты

  • Постов в день создание: 500M × 50 = 25 000 000 000
  • Средний Write RPS: 25,000,000,000 ÷ 86,400 сек = 289 352 RPS
  • Пиковый Write RPS: 289 352 × 3 = 868 056 RPS
    • 3 - примерное значение для peak multiplier. Главное не забудь проговорить про пиковые значения
Объем данных:

Размеры данных на ОДИН пост

Текстовые данные:

  • Текст поста: 500 байт (средний размер)
  • Метаданные: 200 байт
  • Итого текстовых данных: 700 байт на пост

Медиа данные:

  • 70% постов содержат фото (среднее 2 МБ)
  • 30% постов содержат видео (среднее 10 МБ)
  • Средний размер медиа: 4.4 МБ на пост
    • 4.4 - примерное значение

Текстовые данные в день:

  • 25 000 000 000 × 700 = 175 000 000 000 00 байт = 16,298 ГБ/день

Медиа данные в день:

  • 25 000 000 000 × 4.4 МБ = 107 422 000 ГБ/день


ОБЩИЙ объем WRITE данных: 104,920 ТБ/день


Детальное описание архитектуры
Компонент Назначение Технологии (предполагаемые)
GeoDNS, LB, API Gateway Роутинг запросов Nginx/HAProxy
Blob Storage Хранение фотографий AWS S3, Google Cloud Storage
SQL Database (PG) Метаданные юзеров (id, user_id, пути) PostgreSQL с шардированием по id (по сути это user_id)
NoSQL Database (Mongo) Метаданные постов (id, user_id, пути) Mongo с шардированием по post_id
image-processor Пережатие фотографий Асинхронные воркеры (RabbitMQ/Kafka)
Post-Creator Service Посты
Subscribers Service Управление подписками
Feed Cache Кеширование ленты. Отдельный для celebrity и обычных пользователей Redis (шардированный по user_id)
Feed Worker Вычитка из Topic и определение: celeb или нет
Feed Service Лента
Worker Отвечает за мерж ленты
Схема взаимодействий

Сценарий 1: Публикация поста

  • Точка входа: POST v1/post → API Gateway → PostService
  • Последовательность:
    • Фото загружается в Blob Storage.
    • Метаданные сохраняются в SQL DB.
    • image-processor асинхронно генерирует уменьшенные версии.

Сценарий 2: Добавление подписки

  • Точка входа: POST v1/subscribe → API Gateway → Subscribers Service
  • Последовательность:
    • Запись в SQL DB (статус pending).
    • Инвалидация кеша ленты при подтверждении подписки.

Сценарий 3: Получение ленты

  • Точка входа: GET v1/feed → API Gateway → Feed Service
  • Обработка ошибок: Fallback на другие workers с ограничением времени (timeout 400 мс).
Давай подробно разберем варианты хранения постов для ленты

Вариант 1: Запрос подписок из SQL DB (сервис subscribers) → сбор последних постов из cache → мерж → отдача. То есть тут мы храним все посты для всех пользаков. Этот вариант смотрим в данной версии.

  • Плюс: меньше походов в другие сервисы и выше скорость
  • Минус: намного больше RAM

Вариант 2: Хранить в cache только для активных пользаков, а для неактивных ходить в сервис subscribers (чтобы получить подписки), затем идти в сервис posts (чтобы по ID выцепить все посты). А еще при падении Feed делает redirect на сервис Post и выгребать ленту оттуда. Этот вариант разберем в ver 3

  • Плюс: меньше RAM
  • Минус: больше логики и потенциальных задержек

Более мягкая альтернатива: перед сервисом feed можно поставить cache и сначала делать запросы туда. То есть полная лента для 10 постов у каждого юзера. А уже дальше по алгоритму в Вариант 1 или Вариант 2