URL 단축기 시스템 설계: 링크 단축기의 작동 원리
"URL 단축기를 설계하세요"는 가장 인기 있는 시스템 설계 면접 질문 중 하나입니다 — 그럴 만한 이유가 있습니다. 해싱, 데이터베이스, 캐싱, 로드 밸런싱, 분산 시스템을 모두 다루면서도 제품 자체는 속임수처럼 단순합니다.
이 가이드에서는 URL 단축기가 실제로 어떻게 작동하는지, 핵심 설계 결정, 그리고 규모에서의 트레이드오프를 살펴보겠습니다.
기본 흐름
URL 단축기는 두 가지 작업을 수행합니다:
- 1단축: 긴 URL을 받아 짧은 코드를 생성합니다
- 2리다이렉트: 누군가 짧은 URL을 방문하면 원본으로 리다이렉트합니다
높은 수준의 흐름은 다음과 같습니다:
사용자가 짧은 링크 생성:
긴 URL → 짧은 코드 생성 → 매핑 저장 → 짧은 URL 반환
사용자가 짧은 링크 클릭:
짧은 URL → 코드 조회 → 긴 URL 찾기 → 301 리다이렉트
짧은 코드 생성
핵심 과제는 고유하고 짧은 코드를 생성하는 것입니다. 여러 접근 방식이 있습니다:
접근 방식 1: Base62 인코딩
자동 증가하는 ID를 [a-zA-Z0-9] 문자를 사용하여 Base62 문자열로 변환합니다:
- ID
1→1 - ID
62→10 - ID
238,328→ZZZ
7자 Base62 코드는 62^7 = 3.5조 개의 고유 URL을 지원합니다.
장점: 간단하고 예측 가능한 길이, 충돌 없음 단점: 순차 ID는 예측 가능합니다 (사용자가 다른 짧은 URL을 추측할 수 있음)
접근 방식 2: 해싱
해시 함수(MD5, SHA-256)를 긴 URL에 적용하고 처음 N개 문자를 사용합니다:
SHA256("https://example.com/very/long/url") → "a3f2b8c1..." 짧은 코드: "a3f2b8c"
장점: 동일한 입력은 항상 동일한 출력을 생성합니다 (중복 제거) 단점: 해시 충돌을 처리해야 하고, 고정 해시 길이가 공간을 낭비할 수 있음
접근 방식 3: 무작위 생성
무작위 영숫자 문자열을 생성하고 고유성을 확인합니다:
장점: 간단하고 예측 불가능 단점: 모든 생성 시 충돌 검사 필요; 데이터베이스가 채워지면서 느려짐
어떤 접근 방식을 사용할까?
대부분의 프로덕션 시스템은 분산 ID 생성기를 사용하는 Base62 인코딩을 사용합니다. 간단하고 충돌 없으며 성능이 좋습니다. Linkly에서는 유사한 접근 방식을 사용합니다 — URL 단축기 작동 원리에서 덜 기술적인 개요를 읽을 수 있습니다.
데이터베이스 설계
핵심 테이블은 간단합니다:
urls ├── id (기본 키, 자동 증가) ├── short_code (고유 인덱스) ├── long_url (대상) ├── created_at (타임스탬프) ├── user_id (생성자) └── click_count (비정규화된 카운터)
SQL vs. NoSQL
SQL (PostgreSQL, MySQL): ACID 준수, 강한 일관성, 중간 규모에 적합합니다. 대부분의 URL 단축기는 여기서 시작합니다.
NoSQL (DynamoDB, Cassandra): 수십억 개의 URL에 대해 더 나은 수평 확장. 이 사용 사례에서는 최종 일관성이 허용됩니다.
하이브리드: URL 매핑은 SQL (리다이렉트에 강한 일관성 필요), 클릭 분석은 NoSQL 또는 시계열 데이터베이스 (높은 쓰기 볼륨, 최종 일관성이 괜찮음).
리다이렉트 처리
사용자가 짧은 링크를 클릭하면 시스템은:
- 1URL에서 짧은 코드를 파싱합니다
- 2해당하는 긴 URL을 조회합니다
- 3HTTP 리다이렉트 응답을 반환합니다
301 vs. 302 리다이렉트
- 301 (영구): 브라우저가 리다이렉트를 캐시합니다. 서버 요청이 적지만 반복 클릭에 대한 가시성을 잃습니다.
- 302 (임시): 브라우저는 매번 서버에 확인합니다. 요청이 더 많지만 클릭 추적이 더 정확합니다.
대부분의 URL 단축기는 클릭 추적 정확성을 위해 302 리다이렉트를 사용하고, SEO 사용 사례에 대해서는 301을 옵션으로 제공합니다. 이 차이에 대한 자세한 내용은 301 리다이렉트 가이드를 참조하세요.
캐싱
리다이렉트는 빠르게 처리되어야 합니다 — 지연 시간의 모든 밀리초는 사용자 경험에 영향을 미칩니다. 캐싱이 중요합니다:
메모리 내 캐시 (Redis/Memcached)
메모리에서 short_code → long_url 매핑을 캐시합니다:
GET /abc123 → "abc123"에 대해 Redis 확인 → 캐시 히트? 즉시 리다이렉트 반환 → 캐시 미스? 데이터베이스 쿼리, 캐시 결과, 리다이렉트 반환
작은 Redis 인스턴스는 수백만 개의 URL 매핑을 캐시할 수 있습니다. 대부분의 트래픽이 상대적으로 적은 수의 인기 있는 링크로 이동하므로 90% 이상의 캐시 히트율이 일반적입니다.
CDN 캐싱
301 리다이렉트의 경우 CDN 엣지 노드가 리다이렉트 응답을 캐시하고, 원본 서버에 도달하지 않고도 사용자와 가장 가까운 위치에서 제공할 수 있습니다.
분석 및 클릭 추적
클릭 데이터 기록은 쓰기 작업이 많아서 리다이렉트를 느리게 하면 안 됩니다:
비동기 처리
- 1사용자가 짧은 링크를 클릭합니다
- 2시스템이 즉시 리다이렉트를 반환합니다
- 3클릭 이벤트는 메시지 큐(Kafka, RabbitMQ, SQS)로 전송됩니다
- 4백그라운드 작업자가 이벤트를 처리합니다: 사용자 에이전트를 파싱하고, IP를 지리위치 지정하고, 분석을 저장합니다
이는 빠른 리다이렉트 경로를 느린 분석 파이프라인에서 분리합니다.
수집할 데이터
- 타임스탐프
- IP 주소 (지리위치 지정용)
- 사용자 에이전트 (디바이스/브라우저 감지용)
- Referrer 헤더
- 국가, 도시 (IP 지리위치 지정)
확장성 고려 사항
읽기 집약적인 작업 부하
URL 단축기는 매우 읽기 집약적입니다. 전형적인 비율은 읽기 100:쓰기 1입니다. 이는 다음을 의미합니다:
- 무엇보다 리다이렉트 경로를 최적화합니다
- 캐싱을 적극적으로 사용합니다
- 데이터베이스 읽기 복제본
분산 ID 생성
여러 서버에서 자동 증가하는 ID를 사용하면 충돌을 피해야 합니다. 옵션:
- Snowflake IDs: Twitter의 접근 방식 — 타임스탐프, 머신 ID, 시퀀스 번호를 포함합니다
- UUID: 보편적으로 고유하지만 더 깁니다
- ID 범위: 각 서버에 할당할 ID 범위를 지정합니다
지리적 분포
여러 지역에 리다이렉트 서버를 배포합니다. 도쿄의 사용자가 버지니아의 서버로 왕복할 필요가 없어야 합니다.
보안 고려 사항
URL 단축기는 피싱 및 악성코드 배포에 악용될 수 있습니다. 프로덕션 시스템이 필요합니다:
- URL 스캔 — 악성코드 및 피싱 데이터베이스에 대해 대상을 확인합니다
- 레이트 제한 — 악의적인 짧은 링크의 대량 생성을 방지합니다
- 학대 신고 — 사용자가 의심스러운 링크를 신고하도록 합니다
- 미리보기 페이지 — 선택적으로 리다이렉트하기 전에 링크가 어디로 이동하는지 사용자에게 표시합니다
링크 안전 및 클릭 사기 방지에 대해 자세히 알아보세요.
추가 기능
기본 단축 및 리다이렉트를 넘어 프로덕션 URL 단축기는 다음을 추가합니다:
- 커스텀 도메인 — 자신의 도메인을 사용한 브랜드된 짧은 링크
- 커스텀 슬러그 — 무작위 문자 대신 자신의 짧은 코드를 선택합니다
- 만료 — 시간 제한 링크는 특정 날짜 이후에 작동을 멈춥니다
- 암호 보호 — 대상에 접근하려면 암호를 입력해야 합니다
- A/B 테스팅 — 여러 대상 간 순환
- 지리적 타게팅 — 국가별 리다이렉트
- 디바이스 타게팅 — 모바일 vs. 데스크톱에 대한 다양한 대상
- QR 코드 — 모든 짧은 링크에 대해 스캔 가능한 코드 생성
결론
URL 단축기 시스템 설계는 단순하게 시작하지만 복잡함의 계층을 드러내기 때문에 훌륭한 연습입니다: 코드 생성, 데이터베이스 설계, 캐싱, 분석 파이프라인, 학대 방지. 이러한 기본 사항을 이해하면 면접 준비나 자체 도구 구축 여부와 관계없이 도움이 됩니다.
직접 구축하지 않고 프로덕션 URL 단축기를 사용하고 싶으신가요? Linkly 시작하기 — 위에서 설명한 모든 아키텍처가 커스텀 도메인, 분석, 고급 기능과 함께 즉시 사용 가능합니다.
