[대규모 시스템 설계 스터디] 8장 정리

현실도피·2026년 8월 4일
post-thumbnail

이전 포스트: [대규모 시스템 설계 스터디] 7장 정리
다음 포스트: [대규모 시스템 설계 스터디] 9장 정리

8장. URL 단축기 설계

URL 단축 서비스는 긴 URL을 짧은 형태로 변환하고, 사용자가 단축 URL에 접근하면 다시 원래 주소로 이동시키는 서비스다.

예를 들어

https://example.com/very/long/address

↓

https://tinyurl.com/2TX

처럼 긴 주소 대신 짧은 URL을 사용할 수 있도록 만든다.

겉으로 보면 단순하게 문자열 하나를 짧게 바꾸는 기능처럼 보이지만, 실제 대규모 서비스에서는

  • 단축 키의 유일성
  • 빠른 조회
  • 리디렉션
  • 대량의 읽기 요청 처리
  • 데이터 영구 저장
  • 서버와 DB 확장

등을 함께 고려해야 한다.


1. 요구사항 정리

우선 URL 단축 서비스가 제공해야 할 핵심 기능을 정리한다.

URL 단축

사용자가 긴 URL을 입력하면 짧은 URL을 생성한다.

Long URL
   ↓
URL Shortener
   ↓
Short URL

URL 리디렉션

사용자가 생성된 단축 URL에 접근하면 원본 URL로 이동시킨다.

Short URL
   ↓
URL Shortener
   ↓
Original URL

높은 가용성과 확장성

서비스 규모가 커지더라도 계속 요청을 처리할 수 있어야 한다.

즉

대량 Request
+
서버 장애
+
데이터 증가

상황에서도 서비스가 정상적으로 동작하도록 설계해야 한다.


2. 시스템 규모 추정

설계 전에 어느 정도 규모의 시스템인지 계산해본다.

이번 장에서는 다음과 같이 가정한다.

하루 URL 생성
= 1억 개

이를 초당 요청으로 환산하면 약

100,000,000 / 86,400
≈ 1,160 Write / sec

이다.


읽기 요청

URL 단축 서비스는 URL을 만드는 요청보다 기존 URL을 조회하는 요청이 훨씬 많다고 가정한다.

읽기와 쓰기의 비율을

Read : Write
= 10 : 1

로 잡으면

Read QPS
≈ 11,600

정도가 된다.

즉 URL 단축 서비스는 쓰기보다 읽기가 많은 시스템이다.

이 특징은 뒤에서 캐시를 도입하는 중요한 근거가 된다.


3. 저장 공간 추정

하루에 1억 개의 URL을 만들고 이를 10년 동안 보관한다고 가정한다.

1억 × 365 × 10
≈ 3,650억 Records

원본 URL 평균 크기를 약 100Byte로 잡으면

3,650억 × 100Byte
≈ 36.5TB

정도의 저장 공간이 필요하다.

실제 시스템에서는 추가적인 메타데이터와 인덱스 등의 공간도 필요하겠지만, 개략적인 규모를 파악하기 위한 계산이다.


4. API 설계

URL 단축 서비스에서는 크게 두 가지 API가 필요하다.

URL 생성
+
URL 조회

REST 형태로 생각해볼 수 있다.


URL 단축 API

사용자가 원본 URL을 전달하면 새로운 단축 URL을 생성한다.

POST /api/v1/data/shorten

요청 예시

{
  "longUrl": "https://example.com/articles/2026/very-long-address"
}

서버는 이에 대응하는 단축 URL을 반환한다.

https://tinyurl.com/abc1234

5. URL 리디렉션 API

사용자가 단축 URL에 접근하면 서버에서 원본 URL을 조회한다.

개념적으로는

GET /{shortKey}

와 같이 단축 키를 이용한 요청으로 볼 수 있다.

예를 들어

https://tinyurl.com/abc1234

에 접근하면 서버는

abc1234
   ↓
Original URL 조회
   ↓
https://example.com/...

과정을 거친다.

이후 브라우저에 Redirect 응답을 반환한다.


6. URL 리디렉션

사용자가 단축 URL을 클릭하면 다음과 같은 흐름이 발생한다.

Short URL 요청
     ↓
URL Shortener
     ↓
Original URL 조회
     ↓
Redirect Response
     ↓
Original Website

Redirect 응답에서는 대표적으로 301 또는 302 상태 코드를 사용할 수 있다.


7. 301과 302의 차이

301 Moved Permanently

해당 URL이 새로운 URL로 영구적으로 이동했다는 의미다.

Short URL
   ↓
301
   ↓
Original URL

브라우저나 중간 캐시가 Redirect 결과를 저장할 수 있다.

따라서 이후 동일한 단축 URL에 접근할 때 URL 단축 서버를 거치지 않고 기존에 저장된 Redirect 정보를 활용할 가능성이 있다.

장점

URL Shortener 요청 감소
→ 서버 부하 감소

하지만 사용자가 URL 단축 서버를 다시 방문하지 않는다면 클릭 횟수를 서버에서 직접 집계하기 어려워질 수 있다.


302 Found

일시적인 Redirect를 나타낸다.

Short URL
   ↓
302
   ↓
Original URL

단축 URL을 계속 유지하면서 목적지로 보내야 하는 상황에서 활용할 수 있다.

요청이 URL Shortener를 거치는 구조라면

  • 클릭 수 분석
  • 트래픽 분석
  • 목적지 URL 변경

등을 처리하기 편하다.

다만 302라고 해서 항상 절대로 캐시되지 않는다고 단정할 수는 없으며, 실제 캐시 동작은 응답 헤더 등의 정책에도 영향을 받을 수 있다.


8. URL 매핑은 어떻게 저장할까?

URL Shortener가 기억해야 할 핵심 데이터는 다음과 같다.

Short Key → Long URL

예를 들어

2TX
→
https://example.com/very/long/address

형태다.

이를 Key-Value 구조로 바라보면 매우 단순하다.

Key   = 2TX
Value = Original URL

9. 해시 값으로 URL을 복원하는 것은 아니다

처음에는 단축 문자열 자체에서 원본 URL을 다시 복원하는 방식이라고 생각할 수도 있다.

하지만 여기서 다루는 구조는 그렇지 않다.

zn9edcu
   ↓
Database 조회
   ↓
Original URL

즉 zn9edcu라는 단축 키를 이용해서 DB에 저장해둔 원본 URL을 찾는 방식이다.

따라서 서버는 다음과 같은 매핑 정보를 저장해야 한다.

short_key
↔
long_url

10. 해시 테이블만 사용하면 안 될까?

애플리케이션 내부의 Hash Table을 사용하면 매우 빠르게 데이터를 조회할 수 있다.

하지만 일반적인 Hash Table은 메모리에 존재하기 때문에 대규모 URL 데이터를 영구적으로 저장하는 용도로는 한계가 있다.

문제점

  • 서버 종료 시 데이터 손실 가능
  • RAM 비용이 높음
  • 저장 가능한 데이터 양에 한계
  • 여러 서버가 데이터를 공유하기 어려움
  • 백업 및 복구가 어려움

따라서 원본 URL 매핑 정보는 데이터베이스에 저장하고, 자주 조회하는 데이터만 캐시에 보관하는 구조를 생각할 수 있다.

Database
→ 영구 저장

Cache
→ 빠른 조회

11. 데이터 모델

단순한 테이블을 만든다면 다음과 같은 구조를 생각할 수 있다.

ID
short_key
long_url

예를 들어

IDshort_keylong_url
1001abc1234https://example.com/...

와 같은 형태다.

이때 short_key는 중복되면 안 된다.

서로 다른 두 원본 URL이 동일한 단축 키를 가지면 어떤 URL로 Redirect해야 할지 판단할 수 없기 때문이다.

따라서 DB 수준에서도 UNIQUE 제약조건을 사용할 수 있다.

CREATE UNIQUE INDEX idx_short_key
ON url_mapping(short_key);

즉 애플리케이션 로직뿐 아니라 데이터베이스에서도 최종적으로 중복을 막는다.


12. 단축 키는 어떻게 만들까?

핵심 문제는 다음과 같다.

긴 URL을 어떤 짧은 문자열과 연결할 것인가?

단축 키는 다음 문자들을 사용한다고 가정한다.

0 ~ 9  → 10개
a ~ z  → 26개
A ~ Z  → 26개

총

10 + 26 + 26
= 62개

의 문자를 사용할 수 있다.


13. 단축 키 길이

약 3,650억 개 이상의 URL을 표현해야 한다고 가정한다.

6자리 Base62 문자열은 표현 가능한 경우의 수가 부족하지만

62^7

은 수조 개의 조합을 만들 수 있다.

따라서 약 7자리 정도의 단축 키를 사용할 수 있다.

abc123A
z9K20Qa
...

14. 단축 키를 만드는 두 가지 방법

이번 장에서는 크게 두 가지 방법을 비교한다.

1. Hash + Collision Resolution

2. Unique ID + Base62

두 방법 모두 짧은 키를 만들 수 있지만 접근 방식이 다르다.


15. Hash 방식

원본 URL에 해시 함수를 적용한다.

예를 들어

Long URL
   ↓
MD5 / SHA / CRC32
   ↓
Hash Value

와 같은 구조다.

문제는 일반적인 Hash 결과가 단축 URL에 사용하기에는 너무 길다는 것이다.

따라서 결과 중 일부만 사용한다.

전체 Hash
↓
앞 7글자 추출
↓
abc1234

16. Hash 충돌 문제

Hash 결과를 일부만 사용하면 서로 다른 URL이 같은 단축 키를 만들 가능성이 생긴다.

예를 들어

URL A
→ abc1234

URL B
→ abc1234

가 발생할 수 있다.

따라서 충돌을 확인하고 다시 생성하는 과정이 필요하다.


17. 충돌 해결 과정

예를 들어 다음과 같이 처리할 수 있다.

Long URL
   ↓
Hash
   ↓
abc1234
   ↓
DB 확인
   ↓
이미 존재
   ↓
Salt 추가
   ↓
다시 Hash
   ↓
k9x82Qa

과정은 다음과 같다.

  1. 원본 URL Hash
  2. 결과 일부를 Short Key로 선택
  3. DB에서 해당 Key 존재 여부 확인
  4. 없으면 저장
  5. 이미 있다면 Salt 등의 값을 추가
  6. 다시 Hash
  7. 충돌이 없어질 때까지 반복

18. DB의 UNIQUE 제약조건 활용

애플리케이션에서 미리 DB를 조회했다고 해서 충돌이 완전히 사라지는 것은 아니다.

여러 서버가 동시에 같은 Key가 비어 있다고 판단할 수도 있기 때문이다.

따라서 실제 저장 단계에서도

Short Key 생성
      ↓
INSERT
      ↓
UNIQUE 충돌?
  ↙         ↘
No          Yes
↓             ↓
완료        새 Key 생성

형태로 처리할 수 있다.

즉 DB의 UNIQUE 제약조건이 마지막 안전장치 역할을 한다.


19. Bloom Filter 활용

Short Key의 존재 가능성을 빠르게 판단하기 위해 Bloom Filter와 같은 자료구조를 보조적으로 고려할 수도 있다.

새 Short Key
    ↓
Bloom Filter
    ↓
절대 없음
→ 저장 시도

있을 수도 있음
→ 추가 확인

Bloom Filter는

"없다"
→ 확실하게 없음

"있다"
→ 실제로는 없을 수도 있음

이라는 특징을 가진다.

따라서 불필요한 조회를 줄이기 위한 보조 수단으로 활용할 수 있다.

다만 최종적인 중복 여부는 실제 저장소의 상태를 확인해야 한다.


20. Hash 방식의 특징

장점

  • 원본 URL을 기반으로 키 생성 가능
  • 별도의 순차 숫자 ID가 없어도 됨
  • 여러 서버에서 Hash 계산 가능

단점

  • Hash 충돌 가능
  • 충돌 검사 및 재시도 로직 필요
  • 동일한 URL이 여러 번 들어왔을 때 처리 정책 필요
  • 일부 Hash 값만 사용하므로 추가적인 충돌 관리 필요

21. Base62 방식

두 번째 방법은 원본 URL을 바로 Base62로 변환하는 것이 아니다.

먼저 각 URL에 전역적으로 유일한 숫자 ID를 부여한다.

Long URL
   ↓
Unique ID Generator
   ↓
2009215674938

그리고 이 숫자를 Base62 문자열로 변환한다.

2009215674938
   ↓
Base62
   ↓
zn9edcu

이 zn9edcu가 Short Key가 된다.


22. Base62 변환 원리

Base62는 62개의 문자를 숫자처럼 사용하는 방식이다.

예를 들어

0~9
a~z
A~Z

를 하나의 숫자 체계로 사용한다.

10진수를 62로 계속 나누면서 나머지를 문자로 변환한다.

예를 들어 11157을 변환하면

11157 ÷ 62
→ 몫 179
→ 나머지 59

179 ÷ 62
→ 몫 2
→ 나머지 55

2 ÷ 62
→ 몫 0
→ 나머지 2

나머지를 대응되는 문자로 바꾸고 역순으로 읽으면 Short Key가 만들어진다.

예시에서는

2TX

와 같은 결과를 얻을 수 있다.


23. Base62 방식의 전체 흐름

Long URL
   ↓
Unique Numeric ID 생성
   ↓
Base62 변환
   ↓
Short Key
   ↓
DB 저장

예를 들어

Original URL
https://en.wikipedia.org/wiki/Systems_design

에

ID
2009215674938

을 발급한다.

이 숫자를 Base62로 변환해

zn9edcu

라는 Short Key를 만든다.

그러면 DB에는 다음과 같이 저장된다.

IDshort_keylong_url
2009215674938zn9edcuhttps://en.wikipedia.org/wiki/Systems_design

최종 URL은

https://tinyurl.com/zn9edcu

가 된다.


24. Hash 방식과 Base62 방식 비교

Hash 방식

Long URL
   ↓
Hash
   ↓
일부 문자 추출
   ↓
충돌 검사
   ↓
Short Key

URL 자체를 이용해 Key를 만든다.

하지만 충돌 관리가 필요하다.


Base62 방식

Long URL
   ↓
Unique Numeric ID
   ↓
Base62
   ↓
Short Key

유일한 숫자 ID가 보장된다면 Base62 결과 역시 유일하게 만들 수 있다.

대신 유일한 숫자 ID를 생성하는 시스템이 필요하다.

지난 장에서 학습했던 분산 ID 생성기와도 연결할 수 있는 부분이다.


25. URL 생성 전체 흐름

이번에는 Base62 방식을 이용한다고 가정한다.

전체적인 URL 생성 과정은 다음과 같다.

Long URL 입력
      ↓
기존 등록 여부 확인
  ↙             ↘
있음             없음
 ↓                ↓
기존 URL 반환   Unique ID 생성
                  ↓
               Base62
                  ↓
               DB 저장
                  ↓
            Short URL 반환

조금 더 구체적으로 보면

  1. 클라이언트가 Long URL 전송
  2. 기존에 등록된 URL인지 확인
  3. 존재한다면 기존 Short URL 반환
  4. 없다면 Unique ID 생성
  5. ID를 Base62로 변환
  6. ID, Short Key, Long URL 저장
  7. Short URL 반환

과정이다.


26. URL Redirect 상세 설계

URL 단축 서비스는 쓰기보다 읽기 요청이 훨씬 많은 서비스다.

앞에서

Read : Write
= 10 : 1

이라고 가정했다.

따라서 사용자가 단축 URL을 클릭할 때마다 항상 DB를 조회하면 DB 부하가 커질 수 있다.

이를 줄이기 위해 Cache를 사용할 수 있다.


27. 캐시를 활용한 Redirect

자주 사용되는

Short Key
→
Original URL

매핑을 Redis 등의 캐시에 저장한다.

전체적인 흐름은 다음과 같다.

Short URL 요청
      ↓
Load Balancer
      ↓
Web Server
      ↓
Cache 조회
  ↙          ↘
Hit           Miss
 ↓              ↓
Redirect       DB 조회
                ↓
             Cache 저장
                ↓
             Redirect

28. Cache Hit

캐시에 Short Key가 존재한다면

zn9edcu
   ↓
Cache
   ↓
Original URL

즉시 원본 URL을 찾아 Redirect할 수 있다.

DB 조회가 필요하지 않기 때문에 응답 속도가 빠르고 DB 부하도 줄어든다.


29. Cache Miss

캐시에 데이터가 없다면 DB에서 조회한다.

Cache Miss
     ↓
Database
     ↓
Original URL 발견
     ↓
Cache 저장
     ↓
Redirect

다음번 동일한 URL 요청에서는 캐시에서 바로 처리할 수 있다.


30. 존재하지 않는 Short URL

Cache에도 없고 DB에도 해당 Short Key가 존재하지 않는다면 정상적인 URL이 아니다.

Short Key
   ↓
Cache 없음
   ↓
DB 없음
   ↓
오류 반환

잘못 입력했거나 존재하지 않는 단축 URL일 수 있으므로 적절한 오류 응답을 반환한다.


31. Load Balancer의 역할

여기서 Load Balancer가 Cache를 조회한다고 생각하면 안 된다.

Load Balancer의 역할은 요청을 여러 웹 서버로 분산하는 것이다.

               Client
                  ↓
           Load Balancer
             ↙        ↘
       Web Server 1   Web Server 2
             ↓             ↓
             └── Cache / DB ──┘

실제 Short Key 조회는 웹 서버나 관련 서비스가 수행한다.


32. 전체 아키텍처

지금까지의 내용을 하나로 연결하면 다음과 같은 구조를 생각할 수 있다.

              Client
                 ↓
          Load Balancer
                 ↓
        ┌────────────────┐
        │   Web Servers  │
        └────────────────┘
           ↓          ↓
        Cache      Database

URL 생성 요청에서는

Client
  ↓
Web Server
  ↓
ID Generator
  ↓
Base62
  ↓
Database

과정을 사용하고,

URL 조회 요청에서는

Client
  ↓
Web Server
  ↓
Cache
  ↓ Miss
Database

구조를 사용할 수 있다.


33. 서비스가 더 커진다면?

기본적인 URL Shortener를 만들었다면 다음 단계는 확장성을 고려하는 것이다.


Rate Limiter

악의적인 사용자나 Bot이 짧은 시간에 매우 많은 URL 생성 요청을 보낼 수 있다.

Bot
↓↓↓↓↓↓↓↓↓↓
URL 생성 Request

이 경우 앞에서 학습한 Rate Limiter를 이용해 사용자 또는 IP 단위로 URL 생성 횟수를 제한할 수 있다.


Web Server Scale-out

웹 계층을 Stateless하게 구성하면 트래픽에 따라 웹 서버를 추가할 수 있다.

Web Server 1
Web Server 2
Web Server 3
...

Load Balancer는 이 서버들에 요청을 분산한다.


Database 확장

데이터가 계속 증가한다면 하나의 DB로 처리하기 어려워질 수 있다.

이 경우

Replication
또는
Sharding

등의 방법을 고려할 수 있다.


분석 시스템

URL 단축 서비스에서는 단순히 Redirect만 하는 것이 아니라 클릭 데이터를 분석할 수도 있다.

예를 들어

  • 클릭 수
  • 시간대
  • 유입 위치
  • 디바이스
  • 인기 URL

등을 수집하면 서비스 분석에도 활용할 수 있다.


34. 안정성과 가용성

URL Shortener가 대규모 서비스라면

Web Server 장애
Database 장애
Cache 장애

등의 상황도 고려해야 한다.

따라서

  • 서버 다중화
  • DB 복제
  • 캐시 장애 대응
  • 모니터링
  • 데이터 백업

등을 함께 설계해야 한다.


전체 흐름 정리

이번 장의 전체 흐름을 연결하면 다음과 같다.

긴 URL을 짧게 만들고 싶음
        ↓
Short Key 필요
        ↓
어떻게 생성할 것인가?
        ↓
Hash
vs
Unique ID + Base62
        ↓
Short Key 생성
        ↓
DB에
Short Key ↔ Long URL 저장
        ↓
사용자가 Short URL 클릭
        ↓
Load Balancer
        ↓
Web Server
        ↓
Cache 조회
        ↓
Cache Hit
→ 바로 Redirect
        ↓
Cache Miss
→ DB 조회
→ Cache 저장
→ Redirect
        ↓
트래픽 증가
        ↓
Rate Limiter
Web Server Scale-out
DB Replication / Sharding

결국 URL 단축 서비스의 핵심은 단순히 문자열을 짧게 만드는 것이 아니다.

원본 URL에 대응하는 짧고 유일한 식별자를 생성하고, 이를 안정적으로 저장한 뒤 대량의 Redirect 요청을 빠르게 처리하는 시스템을 만드는 것

이라고 이해할 수 있다.


공부하면서 정리한 핵심

처음에는 URL 단축 서비스라고 하면

긴 URL
↓
Hash
↓
짧은 URL

정도로 생각했다.

하지만 실제로는 Hash 결과에서 원래 URL을 복원하는 것이 아니라

Short Key
↓
DB / Cache 조회
↓
Original URL

이라는 구조라는 점이 가장 먼저 정리되었다.

또 Short Key를 만드는 방법도 하나만 존재하는 것이 아니었다.

Hash 방식
→ URL 자체를 이용
→ Collision 처리 필요

Base62 방식
→ Unique ID를 먼저 생성
→ 짧은 문자열로 인코딩

처럼 서로 다른 접근 방법이 존재한다.

특히 지난 장에서 배운 분산 ID 생성기를 이용하면 이번 장의 Base62 방식에서 필요한 Unique Numeric ID를 생성할 수 있다는 점에서 이전 내용과 연결되는 느낌이 들었다.

또 URL 단축 서비스는 생성보다 Redirect 요청이 훨씬 많기 때문에

Database
+
Cache

구조를 사용하여 읽기 요청을 빠르게 처리한다는 점도 중요했다.

결국 이번 장 역시 하나의 기능만 보는 것이 아니라

API
→ ID 생성
→ DB
→ Cache
→ Load Balancer
→ Rate Limiter
→ Scale-out

처럼 이전에 학습한 여러 시스템 구성 요소들이 하나의 실제 서비스 안에서 어떻게 연결되는지를 확인할 수 있었던 장이었다.

profile
현실에서 개발하는 도피입니다..

0개의 댓글