Новостная лента

Классика 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 — асинхронно через очередь, готовые ленты — в кэше.
Проверьте себя
1. В чём главный минус fan-out on write (push)?
AМедленное чтение ленты
BЗапись взрывается для авторов с миллионами подписчиков
CНевозможно ранжировать ленту
DНе работает с кэшем
2. Как обычно решают проблему знаменитостей в ленте?
AЗапрещают популярные аккаунты
BГибрид: push для обычных авторов, pull (подмешивание на чтении) для знаменитостей
CТолько fan-out on read для всех
DТолько fan-out on write для всех
3. Почему fan-out выполняют асинхронно через очередь?
AЧтобы постинг отвечал мгновенно, а раскладка по лентам шла в фоне
BЧтобы лента стала строго согласованной
CЧтобы убрать необходимость в кэше
DОчередь обязательна по протоколу HTTP