Базы данных
System Design: Twitter/X
В 2013 году Beyonce анонсировала беременность на Super Bowl. Twitter рухнул: 5 миллионов подписчиков одновременно открыли ленту, серверы не справились. После этого инцидента Twitter перепроектировал fan-out архитектуру с celebrity exception. Сегодня Maск с 150M подписчиков может публиковать без проблем.
- **Twitter**: Fanout Service + Redis timeline cache для 300M пользователей
- **Instagram**: аналогичная hybrid architecture для Stories и Feed
- **WeChat Moments**: fan-out в пределах friend network (max 5000 friends) = нет celebrity problem
Требования и масштаб
Twitter (X) масштаб: 300 миллионов активных пользователей, 500 миллионов твитов в день, 300,000 QPS на чтение timeline. Функциональные требования: публикация твита, подписки, timeline (лента подписок), поиск. Нефункциональные: timeline за <200ms, consistency eventual (не критична).
Ключевое insight: чтений в 100x больше чем записей. Единственный способ обслуживать 300K timeline QPS - предвычислить timeline и кешировать. Вопрос: когда вычислять - при публикации (fan-out write) или при чтении (fan-out read)?
Twitter: 300K RPS на чтение timeline. Без предвычисления каждый запрос требует JOIN 20+ таблиц. Что произойдёт?
Fan-out on Write vs Fan-out on Read
Fan-out on Write: при публикации твита сразу добавить его в timeline кеш всех подписчиков. Чтение мгновенное. Проблема: celebrity с 100M подписчиков -> 100M write операций при каждом твите. Fan-out on Read: при запросе timeline найти все твиты подписок. Проблема: дорогое чтение.
Twitter изначально использовал Fan-out on Read. При росте нагрузки перешли на Fan-out on Write для обычных пользователей. Знаменитости (celebrities) - исключение: их твиты доставляются через Fan-out on Read чтобы избежать записи в 100M timeline.
Пользователь подписан на Илона Маска (150M подписчиков). Маск публикует твит. Сколько Redis операций выполнит Fan-out on Write?
Timeline Cache архитектура
Twitter использует Redis для хранения precomputed timelines. Каждый пользователь - Redis List с tweet_ids (не полными твитами). Преимущества: компактно, быстро, LPUSH/LRANGE O(1) или O(N). Полные данные твита получаются отдельным запросом (batch lookup).
Аль-Рамз (Fanout service) Twitter: отдельный сервис для fan-out операций. При публикации твита: Fanout service получает событие из Kafka, читает список подписчиков из социального графа, вставляет tweet_id в Redis timeline каждого подписчика. Decoupled от API layer.
Пользователь открывает Twitter после 3 дней отсутствия. Cache timeline мог устареть. Что произойдёт?
Hot Users проблема
Hot Users - аккаунты с миллионами подписчиков (celebrities). Fan-out on Write для них создаёт write storms. Twitter классифицирует пользователей: regular (Fan-out on Write), hot/celebrity (Fan-out on Read при чтении timeline).
Thundering Herd для hot users: Selena Gomez публикует сторис - 400M подписчиков одновременно загружают обновление. Instagram решает через CDN pre-warming: контент заранее распределяется по edge серверам до публикации (для запланированного контента).
Архитектура: 99% пользователей - fan-out on write, 1% celebrities - fan-out on read. Как определить threshold для celebrity?
Hybrid Design: финальная архитектура
Финальная архитектура Twitter: Hybrid fan-out. Regular users: fan-out on write -> Redis timeline cache. Celebrities: fan-out on read при загрузке timeline. Write path через Fanout Service (async via Kafka). Read path: Redis + Tweet Store + User Service.
Твит содержит только tweet_id в Redis timeline. Полные данные твита - в отдельном Tweet Store (может быть Redis Hash или specialised object store). Разделение позволяет обновлять данные твита (новые like counts) без пересоздания timelines.
Twitter хранит все твиты в одной PostgreSQL таблице
Twitter использует полиглот: PostgreSQL для метаданных, Kafka для event streaming, Redis для timeline cache, Cassandra для социального графа, S3 для медиа, Elasticsearch для поиска. Каждый компонент - специализированное решение.
Одна БД не масштабируется до 500M tweets/day. Polyglot persistence - не luxury, а необходимость при масштабе Twitter.
Пользователь удалил твит. В timeline кеше 5 млн подписчиков ещё есть tweet_id. Что сделать?
Итоги
- **Fan-out on Write**: быстрое чтение, дорогая запись; не масштабируется для celebrities
- **Hybrid**: regular users = fan-out write; celebrities = fan-out read; merge при чтении timeline
- **Timeline кеш**: Redis List с tweet_ids (не полными данными); rebuild при miss из БД
Связанные темы
Twitter design использует несколько key concepts:
- Redis — Redis Lists для timeline cache; core infrastructure Twitter feed
- Кеширование — Fan-out on Write = precomputed cache strategy
- Polyglot Persistence — Twitter = PostgreSQL + Redis + Cassandra + S3 + Elasticsearch
Вопросы для размышления
- Как бы ты реализовал "Trending Topics" на Twitter? Какие структуры данных и как часто обновлять?
- Пользователь отписывается от celebrity. Нужно ли чистить celebrity tweets из Redis timeline?
- При шардировании Tweet Store по tweet_id - как эффективно получать последние твиты списка пользователей?