Спроектируйте сервис сокращения ссылок наподобие bit.ly: генерация кода, хранение, редиректы под высокой нагрузкой.
Короткий ответ
- Чтений на порядки больше, чем записей — дизайн вокруг редиректа
- Код — base62 от счётчика или генератор уникальных id, 7 символов хватает надолго
- Хранение: таблица код → URL, TTL и владелец по необходимости
- Редирект 301/302 с горячим кэшем кодов в Redis
- Масштабирование: кэш, реплики чтения, шардирование по коду
- Клики считаем асинхронно через очередь, не в пути редиректа
Read-heavy система: короткий код из base62, редирект из кэша, запись и аналитика — асинхронно и отдельно.
Как сказать вслух
пример ответаСначала фиксирую профиль нагрузки: редиректов в сотни раз больше, чем созданий ссылок, значит оптимизирую чтение. Код генерирую как base62-представление уникального числа — семи символов хватает на триллионы ссылок без коллизий, в отличие от усечённого хэша. Храню пару код-URL в базе, а горячие коды кэширую в Redis, чтобы редирект не ходил в базу. Счётчики кликов не пишу синхронно — кидаю событие в очередь и агрегирую отдельно. Остаётся выбрать 301 или 302: постоянный редирект кэшируется браузером, но тогда мы теряем статистику.
Подробный ответ
Основной ответ
Оценка: допустим, сотни миллионов ссылок и десятки тысяч редиректов в секунду в пике — классическая read-heavy система. Генерация кода: вариант с усечённым хэшем URL страдает от коллизий и требует проверок; надёжнее выдавать уникальный id (диапазоны id, выдаваемые инстансам, или snowflake-подобный генератор) и кодировать в base62 — детерминированно, без коллизий, 62^7 ≈ 3.5 триллиона комбинаций. Схема данных проста (short_code PK, long_url, created_at, expires_at, owner), поэтому подходит и реляционная база с репликами, и key-value хранилище; при шардировании ключ — сам код, что даёт равномерность. Путь редиректа: LB → сервис → Redis (cache-aside, горячие 20% кодов) → база при промахе; несуществующий код — 404, и от перебора кодов защищает rate limit. Аналитика кликов — событие в Kafka и офлайн-агрегация. Выбор 302 вместо 301 сохраняет каждый клик в статистике ценой лишнего запроса к нам.
Ключевые моменты
- Счётчик вместо хэша. Base62 от уникального числа исключает коллизии по построению; хэш требует цикла «проверь-пересоли», который под нагрузкой неприятен.
- 301 vs 302. 301 кэшируется браузером навсегда — трафик и статистика мимо нас; 302/307 оставляет контроль и аналитику. Это любимый вопрос-ловушка.
- Кэш решает всё. Распределение кликов сильно скошено: маленький Redis-кэш снимает основную долю чтений с базы.
- Ничего лишнего в hot path. Инкременты счётчиков, логирование, обогащение — асинхронно; редирект должен быть одним lookup-ом.
Практический контекст
Это самая частая разминочная задача системного дизайна: интервьюер проверяет структуру рассуждения — оценка нагрузки, API, схема данных, узкие места — а не экзотику. Сильного кандидата выдают детали: аргументированный выбор base62-счётчика против хэша, осознанный ответ про 301/302, вынос аналитики из пути редиректа и слова про TTL и чистку истёкших ссылок.
Частые ошибки
- Начинают с генерации кода, не оценив соотношение чтений и записей
- Берут усечённый MD5 и не могут объяснить обработку коллизий
- Выбирают 301, не осознавая потерю статистики из-за кэширования браузером