Какие данные нужно хранить для сервиса коротких ссылок
Что проверяют
Вопрос из system design: умеете ли вы отделить минимально нужные данные от желательных и понимаете ли, что чтение здесь на порядки чаще записи. Следом спрашивают, как генерировать короткий код и где хранить статистику переходов.
Как отвечать
Начните с уточнения нагрузки и требований: нужны ли пользователи, свои алиасы, срок жизни, аналитика. Потом разделите данные.
- ядро: короткий код (уникальный, он же ключ поиска), исходный URL,
created_at. Этого достаточно для редиректа; - опционально:
expires_at,owner_id, признак пользовательского алиаса, статус (активна, заблокирована за фишинг), хеш исходного URL, если одинаковые ссылки нужно склеивать; - переходы: отдельный поток событий, а не счётчик в строке ссылки. Время, код, реферер, страна, тип устройства. Пишутся в Kafka или сразу пачками в ClickHouse, агрегаты считаются там же.
Генерация кода: base62 от последовательного id (7 символов дают 62^7, около 3,5 трлн вариантов), случайная строка с проверкой коллизии через уникальный индекс или обрезанный хеш URL. Последовательные коды легко перебрать, поэтому для приватных ссылок их перемешивают.
Прикиньте объём: запись занимает порядка нескольких сотен байт, сто миллионов ссылок это десятки гигабайт, влезает в один PostgreSQL. Горячие коды держат в Redis.
В Go обработчик редиректа делает поиск по коду и http.Redirect(w, r, url, http.StatusFound), а событие перехода отправляет в буферизованный канал или продюсер, не задерживая ответ.
Где спотыкаются
Делают click_count колонкой и увеличивают её на каждом переходе. Популярная ссылка превращается в горячую строку с блокировками.
Отвечают 301 и удивляются пропавшей статистике: браузер кэширует постоянный редирект и больше не ходит в сервис. Для учёта переходов нужен 302 или 307.
Хранят полные IP-адреса без нужды. Это персональные данные, для аналитики хватит страны и обрезанного адреса.