Спроектируйте сервис «топ-100 популярных запросов» за последний час и за день.
- Как посчитать трендовые хештеги?
- Как найти самые популярные товары в реальном времени?
Две дорожки: быстрая приближённая — потоковые агрегаторы считают топ по минутным окнам (count-min sketch + куча или Space-Saving) и сливают в топ за час; медленная точная — пакетный подсчёт по сырым событиям для дня и отчётов.
- Поток в Kafka, партиционирование по ключу запроса — один ключ считает один агрегатор
- Окно часа = 60 минутных корзин, старые выбрасываются
- Результат — готовый список в кэше, чтение мгновенное
А ещё Нормализация запросов (регистр, опечатки) важнее алгоритма
Подробно
Требования: топ-100 поисковых запросов за последний час (обновление раз в минуту) и за день; допустима небольшая неточность для часового; чтение топа — тысячи раз в секунду. Оценка: 100 000 запросов в секунду, сотни миллионов разных строк в день.
Ввод: события поиска → Kafka. Предварительно — нормализация (регистр, пробелы, синонимы, отсев ботов и мусора).
Быстрая дорожка:
- партиционирование событий по хешу запроса — все события одного запроса попадают к одному агрегатору, и его счётчик точен в пределах узла (иначе нужно сливать частичные топы с запасом);
- агрегатор держит счётчики за текущую минуту. Если различных ключей слишком много — count-min sketch + мин-куча на K (или Space-Saving на несколько тысяч элементов);
- раз в минуту агрегатор отдаёт свой локальный топ (с запасом, например 1000) и закрывает минутную корзину;
- сервис слияния хранит 60 минутных топов каждого агрегатора, складывает по ключам и берёт топ-100 за час. Поскольку ключи разделены по агрегаторам, слияние — просто объединение;
- результат — в 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 при большом числе ключей, горячие ключи.
- Тренды как отличие от базовой частоты — плюс.
Частые ошибки
- Сливать топы с узлов, где один ключ мог считаться на нескольких, без запаса.
- Хранить счётчик каждого запроса за всё время в одной базе и сортировать на лету.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Хранить все запросы в одной таблице и сортировать её на каждый запрос
- ✗Считать топ одним агрегатором без партиционирования
- ✓Приближённая дорожка на скетчах и точная пакетная
- ✗Окно часа пересчитывать с нуля каждую секунду по сырым событиям
Связанные вопросы
- Как найти самые популярные элементы в бесконечном потоке событий? Senior
- Спроектируйте счётчик просмотров для видео с миллионами просмотров в минуту. Middle
- Что такое двоичная куча и очередь с приоритетом? Junior
- Что делать с горячими ключами, на которые приходится непропорционально большая нагрузка? Senior
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.