URL Shortener 설계

발행: (2026년 3월 1일 오후 01:44 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

위의 소스 링크에 있는 전체 텍스트를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다. 코드 블록, URL 및 마크다운 형식은 그대로 유지하고, 본문만 번역해 드립니다. 부탁드립니다.

Requirements

Core

  • 사용자는 긴 URL에서 짧은 URL을 만들 수 있습니다.
  • 짧은 URL을 방문하면 원래 URL로 리다이렉트됩니다.

Optional

  • 사용자 지정 별칭 (예: short.ly/myname)
  • 링크 만료 시간
  • 분석 (클릭 수, 지리 위치, 디바이스 정보)
  • 고가용성 (서비스가 거의 다운되지 않음)
  • 저지연 리다이렉션 (리다이렉션이 즉시 이루어지는 느낌)
  • 대규모 확장성 (수백만 개의 URL, 수십억 건의 리다이렉션)
  • 내구성 있는 저장소 (서버가 충돌해도 데이터 손실 없음)

가정 및 부하 추정

  • 10 M 신규 URL(들) 매월
  • 1 B 리다이렉트 매월
  • Read‑to‑write ratio: ~100:1

시사점

  • 시스템은 읽기 중심이다.
  • 캐싱이 핵심이다.
  • 데이터베이스는 수평 확장이 필요하다.
  • 쓰기는 관리 가능하지만, 읽기는 급증할 수 있다.

고수준 아키텍처

Client ──► Load Balancer ──► URL Generation Service ──► Key‑Value Store
                     │                                 │
                     ▼                                 ▼
                Redirection Service ◄── Cache (Redis) ◄───

쓰기 경로 (짧은 URL 생성)

  1. POST /shorten 요청이 로드 밸런서에 도착합니다.
  2. URL Generation Service가 고유한 짧은 코드를 생성합니다.
  3. 매핑(short_code → long_url)이 키‑값 데이터베이스에 저장됩니다.
  4. 짧은 URL이 클라이언트에게 반환됩니다.

읽기 경로 (리다이렉션)

  1. GET /{short_code} 요청이 로드 밸런서에 도달합니다.
  2. Redirection Service가 캐시(예: Redis)를 확인합니다.
  3. 캐시 히트: 즉시 HTTP 301/302 리다이렉션을 반환합니다.
  4. 캐시 미스: 데이터베이스에서 매핑을 가져와 캐시에 채운 뒤 리다이렉션합니다.

API 사양

짧은 URL 생성

POST /shorten
Content-Type: application/json
{
  "long_url": "https://example.com/very/long/url",
  "custom_alias": "optional",
  "expiry": "optional timestamp"
}

응답

{
  "short_url": "https://short.ly/abc123"
}

리다이렉트

GET /{short_code}

응답 – 원본 URL로 HTTP 301 또는 302 리다이렉트.

ID 생성 전략

자동 증가 ID + Base62

  • 숫자 ID를 증가시킵니다.
  • ID를 Base62(a‑zA‑Z0‑9)로 변환합니다.
  • 고유성을 보장하고, 결정적이며 확장하기 쉽습니다.

해시 기반

  • 긴 URL을 해시하고 처음 6–8자를 사용합니다.
  • 문제: 충돌 가능성 → 충돌 해결이 필요합니다.

복합 (타임스탬프 + 머신 ID + 시퀀스)

  • 여러 서버가 동시에 ID를 생성할 때 유용합니다.
  • 높은 확장성과 고유성을 제공합니다.

샤딩

  • 샤드 키: hash(short_code) % N
  • 장점: 고른 분산, 핫스팟 방지, 간단한 조회.

데이터베이스 복제

  • Primary node: 쓰기(새 짧은 URL)를 처리합니다.
  • Read replicas: 리다이렉트를 제공합니다.

Advantages

  • 읽기가 트래픽을 지배하므로 읽기를 독립적으로 확장할 수 있습니다.
  • 가용성이 향상됩니다; 기본 노드가 실패하면 복제본을 승격시킬 수 있습니다.

캐싱 레이어

  • 캐시 키: short_code → long_url.
  • 일반적인 캐시: Redis 또는 인‑메모리 스토어.

캐시 워크플로우

  1. Redis 확인.
  2. 히트 시 → 즉시 리다이렉트.
  3. 미스 시 → DB 조회, 캐시 업데이트 후 리다이렉트.

캐시 튜닝

  • 엔트리 TTL (선택 사항).
  • LRU 제거 정책.
  • 인기 URL을 위해 캐시 사전 워밍.

분석 및 클릭 카운팅

클릭 수를 동기식으로 업데이트하면 리다이렉트가 느려집니다.

더 나은 접근법

  1. 클릭 이벤트를 메시지 큐(Kafka, RabbitMQ 등)로 전송합니다.
  2. 백그라운드 워커가 이벤트를 소비하고 분석을 비동기적으로 업데이트합니다.

혜택

  • 리다이렉트 경로를 빠르게 유지합니다.
  • 분석을 사용자 경험과 분리합니다.
  • 독립적인 스케일링을 가능하게 합니다.

엣지 케이스 및 트레이드‑오프

  • Custom alias collisions: 거부하거나 사용자가 다른 별칭을 선택하도록 안내합니다.
  • Short code collisions: 결정론적 생성(자동 증가)을 사용하거나 재시도로 충돌을 해결합니다.
  • Malicious/spam URLs: URL 안전 검사를 통합합니다(예: Google Safe Browsing).
  • Expired links: 410 Gone 또는 사용자 정의 오류 페이지를 반환합니다.
  • 301 vs 302: 대부분의 서비스는 나중에 대상 변경을 허용하기 위해 302를 선호합니다.

요약

URL 단축 서비스는 전형적인 읽기‑집중 시스템입니다. 적극적인 캐싱, 읽기 복제본, 비동기 분석을 활용해 리디렉션 경로를 최적화하는 것이 낮은 지연 시간과 높은 확장성을 위해 필수적입니다. 설계 결정—예를 들어 ID 생성, 샤딩, 캐시 정책—은 고유성, 성능, 운영 단순성의 균형을 맞춰야 합니다.

0 조회
Back to Blog

관련 글

더 보기 »