Новостная лента
Классика senior-собеседований: спроектировать ленту подписок и разобраться с fan-out.
Fan-out — стратегия доставки нового поста подписчикам: «на запись» (заранее разложить по лентам) либо «на чтение» (собирать ленту в момент запроса).
Требования и масштаб
Функционально: публиковать пост, видеть ленту постов тех, на кого подписан. Нефункционально: лента грузится быстро, допустима лёгкая итоговая согласованность (новый пост может появиться с задержкой в секунды). Масштаб read-heavy: ленту открывают намного чаще, чем постят.
Две стратегии fan-out
| Fan-out on write (push) | Fan-out on read (pull) |
| При посте кладём его в ленты всех подписчиков | При запросе собираем ленту из постов подписок |
| Чтение быстрое (готовая лента) | Чтение тяжелее (сбор на лету) |
| Запись дорогая для популярных авторов | Запись дешёвая |
Проблема знаменитостей
Fan-out on write ломается на аккаунтах с миллионами подписчиков: один пост порождает миллионы вставок в ленты. Решение — гибрид: для обычных авторов push (готовая лента), а посты «знаменитостей» подмешивать на чтении (pull). Так массовая запись не взрывается, а обычные пользователи получают быстрый отклик.
Высокоуровневая схема
Пост -> App -> [Очередь fan-out] -> запись в ленты подписчиков (кэш)
Лента -> App -> [Cache: feed:user_id] --промах--> собрать + закэшироватьКак работает под капотом
Готовые ленты держат в кэше (например, список id постов на пользователя в Redis). Fan-out on write выполняют асинхронно через очередь, чтобы постинг отвечал мгновенно. Ранжирование (по времени или по «интересности») применяют поверх собранного набора. Гибрид push+pull — это, по сути, оптимизация под распределение: 99% авторов дёшевы для push, а редкие знаменитости обрабатываются отдельно.
Частые ошибки
- Слепой fan-out on write без учёта знаменитостей -> взрыв записи.
- Чистый fan-out on read для всех -> медленная лента под нагрузкой.
- Делать fan-out синхронно в запросе постинга.
Итог
- Лента read-heavy: выбираем между push (быстрое чтение) и pull (дешёвая запись).
- Знаменитости ломают чистый push -> гибрид push+pull.
- Fan-out — асинхронно через очередь, готовые ленты — в кэше.