Спроектируйте ленту новостей социальной сети: пользователь видит посты тех, на кого подписан, отсортированные по времени или релевантности.
Короткий ответ
- Два подхода: fan-out on write и fan-out on read
- Push: при публикации пост раскладывается в ленты подписчиков
- Pull: лента собирается из постов подписок при запросе
- Гибрид: у знаменитостей pull, у обычных push
- Ленты храним в Redis как списки идентификаторов постов
- Тела постов и профили подтягиваем отдельным сервисом
- Пагинация курсором, а не offset
Рабочее решение — гибридный fan-out: push для обычных авторов, pull для миллионников, ленты в Redis, тела постов отдельно.
Как сказать вслух
пример ответаЯ бы начал с выбора между push- и pull-моделью и сразу назвал проблему знаменитостей: раскладывать пост миллионам подписчиков дорого. Поэтому предложу гибрид. Ленту храню как список id в Redis, а содержимое постов достаю батчем по этим id.
Подробный ответ
Основной ответ
Ключевое решение — стратегия fan-out. Fan-out on write: при публикации воркер через очередь добавляет id поста в закэшированные ленты всех подписчиков; чтение дешёвое, запись дорогая. Fan-out on read: лента собирается в момент запроса слиянием последних постов подписок; запись дешёвая, чтение дорогое. Для авторов с миллионами подписчиков push создаёт лавину записей, поэтому их посты подмешиваются на чтении — получается гибрид. Лента в Redis хранит только id постов (например, sorted set по времени), тела постов, лайки и авторов добирает отдельный сервис батч-запросом. Ранжирование накладывается поверх уже собранного списка кандидатов.
Ключевые моменты
- Проблема знаменитости. Push-модель для автора с 10 млн подписчиков означает 10 млн записей на один пост — таких авторов обслуживают pull-веткой.
- Лента как список id. В кэше лежат только идентификаторы; денормализация тел постов в каждую ленту раздула бы память и усложнила редактирование.
- Очередь на записи. Fan-out выполняется асинхронно воркерами: публикация подтверждается сразу, ленты доезжают с небольшой задержкой — это приемлемая eventual consistency.
- Курсорная пагинация. Курсор по времени или id стабилен при вставке новых постов, offset при живой ленте дублирует и теряет элементы.
Практический контекст
Интервьюер проверяет, знаете ли вы компромисс push/pull и догадаетесь ли про гибрид без подсказки. Стоит уточнить: какой размер ленты хранить (обычно сотни последних id), нужна ли хронология или ранжирование, что показывать новому пользователю (fallback на популярное). Полезно проговорить инвалидацию при удалении поста и поведение при недоступности кэша.
Частые ошибки
- Выбирают чистый push или чистый pull и не замечают проблему авторов-миллионников
- Кладут в ленту целые посты вместо идентификаторов и получают дублирование данных
- Предлагают SQL-join по подпискам на каждый запрос ленты при десятках миллионов пользователей