Как спроектировать URL-сокращатель (архитектура, БД, нагрузка)?
Подробный ответ
Уточнение требований
Перед проектированием нужно выяснить: сколько ссылок создаётся и открывается в секунду, каково соотношение read/write, нужны ли пользовательские alias, срок жизни ссылки, аналитика переходов, редактирование, авторизация, защита от spam и географическое распределение.
API
POST /api/v1/urls
{
"url": "https://example.com/very/long/path",
"custom_alias": "optional",
"expires_at": "optional"
}
Response:
{
"short_url": "https://sho.rt/aB3x9K"
}
GET /{short_code}
Response: HTTP 302 or 301 redirectВысокоуровневая архитектура
Client
|
CDN / WAF / Rate Limiter
|
Load Balancer
|
+---------------------------+
| URL API instances |
+---------------------------+
| |
ID generator Redis / Memcached
| |
Primary database <-- cache miss
|
Analytics event queue
|
Stream processing / analytics storageМодель данных
urls:
short_code: string, primary key
original_url: string
created_at: timestamp
expires_at: timestamp, nullable
user_id: string, nullable
is_active: boolean
click_events:
short_code: string
timestamp: timestamp
country: string, nullable
user_agent: string, nullableГенерация короткого кода
Один из вариантов — получить уникальный числовой ID из выделенного ID generator, диапазона ID или атомарного счётчика, а затем закодировать число в Base62. Base62 использует символы a-z, A-Z и 0-9, поэтому даёт короткие URL.
Альтернатива — случайный код с проверкой коллизии в БД. Такой подход проще для небольшого сервиса, но при высокой нагрузке требует продуманной обработки коллизий и может создавать лишние обращения к хранилищу.
Путь редиректа
Проверить short code в cache.
При cache hit вернуть redirect.
При miss прочитать запись из БД, проверить expiration и active status.
Сохранить результат в cache с TTL.
Асинхронно отправить click event в очередь для аналитики.
Масштабирование и надёжность
разделить write-path создания ссылок и read-path редиректов;
кэшировать популярные short code в Redis или CDN;
шардировать БД по short code или диапазону ID при росте данных;
делать analytics асинхронной, чтобы она не замедляла redirect;
применять rate limit, URL validation, abuse detection и blacklist вредоносных ссылок;
использовать 302, если destination может меняться, и осознанно выбирать 301 для постоянных редиректов.
Как ответить на собеседовании
URL shortener обычно read-heavy. Я разделяю создание ссылок и быстрый redirect-path, запускаю stateless API за load balancer, кладу Redis перед БД и генерирую уникальный ID с Base62-кодированием. Click analytics отправляю асинхронно в очередь, а для защиты добавляю rate limit, валидацию URL, expiration и monitoring cache hit rate.
Оцени свой прогресс