PRO

Как спроектировать URL-сокращатель (архитектура, БД, нагрузка)?

URL-сокращатель должен создавать короткий уникальный код для длинной ссылки и быстро перенаправлять пользователя на исходный URL. Для read-heavy нагрузки используют stateless API за load balancer, cache перед хранилищем, масштабируемую БД и генерацию уникальных идентификаторов с Base62-кодированием.
Подробный ответ

Уточнение требований

Перед проектированием нужно выяснить: сколько ссылок создаётся и открывается в секунду, каково соотношение 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.

Альтернатива — случайный код с проверкой коллизии в БД. Такой подход проще для небольшого сервиса, но при высокой нагрузке требует продуманной обработки коллизий и может создавать лишние обращения к хранилищу.

Путь редиректа

  1. Проверить short code в cache.

  2. При cache hit вернуть redirect.

  3. При miss прочитать запись из БД, проверить expiration и active status.

  4. Сохранить результат в cache с TTL.

  5. Асинхронно отправить 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.

Оцени свой прогресс

Честно оцени своё понимание этого вопроса, чтобы мы могли построить твой учебный трек максимально эффективно.
Читать в блоге