Получить доступ

Спроектируйте сервис «топ-100 популярных запросов» за последний час и за день.

SeniorЗадачи на проектирование
Ещё спрашивают так:
  • Как посчитать трендовые хештеги?
  • Как найти самые популярные товары в реальном времени?
Коротко

Две дорожки: быстрая приближённая — потоковые агрегаторы считают топ по минутным окнам (count-min sketch + куча или Space-Saving) и сливают в топ за час; медленная точная — пакетный подсчёт по сырым событиям для дня и отчётов.

  • Поток в Kafka, партиционирование по ключу запроса — один ключ считает один агрегатор
  • Окно часа = 60 минутных корзин, старые выбрасываются
  • Результат — готовый список в кэше, чтение мгновенное

А ещё Нормализация запросов (регистр, опечатки) важнее алгоритма

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Требования: топ-100 поисковых запросов за последний час (обновление раз в минуту) и за день; допустима небольшая неточность для часового; чтение топа — тысячи раз в секунду. Оценка: 100 000 запросов в секунду, сотни миллионов разных строк в день.

Ввод: события поиска → Kafka. Предварительно — нормализация (регистр, пробелы, синонимы, отсев ботов и мусора).

Быстрая дорожка:

  1. партиционирование событий по хешу запроса — все события одного запроса попадают к одному агрегатору, и его счётчик точен в пределах узла (иначе нужно сливать частичные топы с запасом);
  2. агрегатор держит счётчики за текущую минуту. Если различных ключей слишком много — count-min sketch + мин-куча на K (или Space-Saving на несколько тысяч элементов);
  3. раз в минуту агрегатор отдаёт свой локальный топ (с запасом, например 1000) и закрывает минутную корзину;
  4. сервис слияния хранит 60 минутных топов каждого агрегатора, складывает по ключам и берёт топ-100 за час. Поскольку ключи разделены по агрегаторам, слияние — просто объединение;
  5. результат — в Redis/кэш: top:hour — готовый список.

Медленная дорожка: сырые события → ClickHouse/хранилище; раз в час и раз в сутки точный GROUP BY query ORDER BY count DESC LIMIT 100 (или topK). Дневной топ берётся отсюда; часовой можно сверять.

Горячие ключи: один запрос («погода») может давать заметную долю трафика и перегрузить свой агрегатор. Предагрегирование на приёмниках (локальные счётчики за секунду) снижает число событий в разы.

Тренды — не самые частые, а самые выросшие: сравнение частоты в текущем окне с базовой (вчера в это же время, среднее за неделю) с порогом и сглаживанием, иначе в трендах всегда «погода» и «ютуб».

Отказы: агрегатор упал — перечитать партицию с последнего зафиксированного смещения; состояние окна можно восстанавливать из снимков (Flink, Kafka Streams делают это сами).

Пример

Kafka "searches" (64 партиции, ключ = нормализованный запрос)
→ 64 агрегатора: минутная корзина {query: count} → локальный топ-1000
→ merge: окно 60 минут × 64 топа → топ-100 → Redis top:hour (TTL 2 мин)
→ API GET /top?window=hour → из Redis, p99 < 5 мс
Параллельно: ClickHouse, точный топ за сутки каждый час.

Что хотят услышать

  • Разделение на приближённую потоковую и точную пакетную обработку.
  • Партиционирование по ключу и слияние локальных топов.
  • Скользящее окно из минутных корзин.
  • Count-min / Space-Saving при большом числе ключей, горячие ключи.
  • Тренды как отличие от базовой частоты — плюс.

Частые ошибки

  • Сливать топы с узлов, где один ключ мог считаться на нескольких, без запаса.
  • Хранить счётчик каждого запроса за всё время в одной базе и сортировать на лету.

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем