Core Problem
Проектирование масштабируемой ленты социальной сети требует баланса между эффективностью записи и производительностью чтения при работе с постами, подписками и персонализированными лентами.
Стратегии формирования ленты
Существует два основных подхода:
- Fan-out on Write — когда пользователь публикует пост, немедленно отправляем твит всем подписчикам в их предвычисленные кэши ленты
- Fan-out on Read — собираем ленту динамически в момент запроса, запрашивая аккаунты, на которые подписан пользователь
Компромиссы
Fan-out on Write:
- Плюсы: чтение выполняется очень быстро, простое получение ленты из кэша
- Минусы: дорогие записи для аккаунтов с большим числом подписчиков; знаменитость с 10M подписчиков вызывает 10M записей в кэш на один твит
Fan-out on Read:
- Плюсы: дешевые записи, всегда отражает актуальные данные
- Минусы: медленное чтение, требующее агрегации данных потенциально тысяч аккаунтов
Гибридный подход (рекомендуется)
Стандартный для индустрии подход сегментирует пользователей по количеству подписчиков:
Regular users → fan-out on write (предвычисленные ленты)
Celebrity users → fan-out on read (собираются в момент запроса)
При чтении лента пользователя собирается путем слияния его предвычисленной ленты с твитами знаменитостей, подтягиваемыми по запросу.
Ключевые оптимизации
- Используй порог (например, 1M подписчиков) для классификации знаменитостей и обычных аккаунтов
- Храни предвычисленные ленты в in-memory кэшах вроде Redis для чтения с задержкой в микросекунды
- Используй очереди сообщений (например, Kafka) для асинхронной обработки fan-out записей в масштабе
- Применяй пагинацию и ленивую загрузку для ограничения объема данных, получаемых за один запрос
Хранение данных
- Твиты: распределённая база данных (Cassandra) для высокой пропускной способности записей
- Граф подписок: графовая база данных или списки смежности в Redis
- Предвычисленные ленты: Redis sorted sets, отсортированные по timestamp