Как спроектировать сервис сокращения ссылок и что нужно учесть
Что проверяют
Умеете ли вы вести system design от требований и цифр к схеме, а не начинать с набора технологий. Главный уточняющий вопрос: как именно генерируется короткий код и что происходит при коллизии.
Как отвечать
Начните с требований и оценки. Чтений на порядки больше, чем записей, типичное допущение 100 к 1. При 100 млн новых ссылок в месяц за пять лет наберётся 6 млрд записей, а семь символов Base62 дают 62 в седьмой степени, около 3,5 трлн кодов, запаса хватает. Затем ключевые решения:
- генерация кода: счётчик плюс Base62 или случайный код. Счётчик берётся из последовательности PostgreSQL или выдаётся диапазонами каждому инстансу, коллизий нет, но коды предсказуемы. Случайный код из модуля
secretsвставляется под уникальным ограничением, при конфликте повтор. Обрезанный MD5 от URL даёт коллизии и один код на одинаковые ссылки, это надо выбирать осознанно; - хранение: таблица с
short_code,long_url,created_at,expires_at,owner_idи первичным ключом по коду. Строки маленькие, чтение идёт по ключу, при росте добавляются реплики; - редирект:
GET /{code}отдаёт301или302. 301 кешируется браузером и снимает нагрузку, но повторные клики до сервера уже не дойдут, поэтому ради аналитики берут 302; - кеш: Redis перед базой для горячих кодов с политикой
allkeys-lru; - аналитика: клик уходит событием в очередь, а не отдельным
UPDATEв пути редиректа; - защита: rate limit на создание, проверка URL по спискам фишинга, запрет редиректа на внутренние адреса.
На Python API пишется на FastAPI, редирект держит асинхронный драйвер asyncpg.
Где спотыкаются
Называют Base62 хешированием. Это кодирование числа алфавитом из 62 символов, коллизий оно само не создаёт и не устраняет.
Сразу дробят сервис на микросервисы, хотя запись здесь редкая, а редирект это одно чтение по ключу.
Не выбирают между 301 и 302 осознанно и не могут объяснить, почему после перехода на 301 статистика кликов просела.