8장. URL 단축기 설계

2025. 7. 14. 00:54·📝 끄적끄적/📖 가상 면접 사례로 배우는 대규모 시스템 설계 기초
가상 면접 사례로 배우는 대규모 시스템 설계 기초를 읽고 정리한 글입니다.

 

 

이 책 내용을 들어가기에 앞서 왜 대규모 시스템에서 URL을 단축해야 할까? 의문이 들어 찾아봤다.

아래 표는 단축 URL의 주요 장점과 설명을 정리한 것이다.

구분 설명
공간 절약 및 가독성 향상 SNS(예: 트위터 280자 제한)나 문자메시지(SMS)처럼 짧은 메시지 환경에서는 긴 URL이 불편을 초래한다. 단축 URL은 글자 수를 절약하고, 깔끔하게 링크를 전달할 수 있다.
클릭 추적 및 분석 언제, 어디서, 누가 클릭했는지 등 실시간 데이터 추적이 가능하다. 국가/도시별, 시간대별, 디바이스·브라우저별, 유입경로까지 세분화된 분석이 가능하다.
마케팅 효과 측정 다양한 채널에 뿌려진 링크별로 성과를 비교할 수 있고, 메시지별 A/B 테스트나 ROI(투자대비수익률) 계산이 가능하다.
링크 관리 및 업데이트 일부 서비스는 리디렉션 대상 URL을 변경할 수 있어서 웹사이트 구조 변경, 오타 수정, 시즌별 캠페인 등에 유용하게 쓸 수 있다.
주소 마스킹 기능 원래 URL을 감춰 보안이나 브랜딩 관점에서 유리하다. 민감한 정보 노출을 막거나, 짧고 인상적인 링크를 쓸 수 있다.
스팸 및 봇 클릭 방지 비정상 트래픽(봇 등)을 필터링해 광고비 낭비를 막고, 통계의 정확성을 높일 수 있다.

위와 같은 여러 장점이 있지만, 내가 생각하기에 단축 URL의 가장 큰 강점은 가독성을 높여주는 점과 클릭 추적을 통해 마케팅 효과를 극대화할 수 있다는 점이라고 본다.

 

특히 요즘 토스, 무신사, 당근, 지그재그 같은 서비스들에서 사용자들끼리 링크를 공유해 유입률을 높이는 마케팅 전략을 많이 사용하고 있다.

이 부분에서 단축 URL을 사용하면 큰 이점이 있지 않을까? 생각했다.


개발 커뮤니티 단톡방에서 본 이야기인데,
요즘 이런 이벤트를 진행하는 이유는 사용자가 이벤트에 참여할 때 약관 동의 과정에서 데이터를 수집하는 것이 목적이고,

동시에 DAU를 증가시켜 광고 단가를 올리기 위한 목적도 있다고 들었다.

 


실제로 수집하는 항목이 꽤 많다.(이벤트 참가할 때 유의 깊게 봐야 할 듯..)

  • 참고한 글
    왜 긴 링크를 짧게 줄여서 사용할까? 단축URL을 사용하는 이유!
    단축 URL을 사용하여 실시간 클릭 수를 추적하는 방법

 

 

1단계 문제 이해 및 설계 범위 확정

시스템 설계 면접 문제는 의도적으로 어떤 정해진 결말을 갖지 않도록 만들어진다 따라서 면접장에서 시스템을 성공적으로 설계해 내려면 질문을 통해 모호함을 줄이고 요구사항을 알아내야 한다.

질문 예시

  • 어떻게 동작해야하는지 예제를 보여주실 수 있을까요?
  • 트래픽 규모는 어느정도 일까요?
  • 단축 URL의 길이는 어느 정도여야 하나요?
  • 단축 URL에 포함될 문자에 제한이 있습니까?
  • 단축 URL을 시스템에서 지우거나 갱신할 수 있습니까?

이 시스템의 기본적 기능은 아래와 같다.

  1. URL 단축 : 주어진 긴 URL을 훨씬 짧게 줄인다.
  2. URL 리다이렉션(redirection): 축약된 URL로 HTTP 요청이 오면 원래 URL로 안내
  3. 높은 가용성과 규모 확장성, 그리고 장애 감내가 요구됨

 

개략적 추정

  • 쓰기 연산: 매일 1억 개의 단축 URL 생성
  • 초당 쓰기 연산: 1억 / 24 / 3600 = 1160
  • 읽기 연산: 읽기 연산과 쓰기 연산 비율은 10:1이라고 하자. 그 경우 읽기 연산은 초당 11,600회 발생한다(1160 x 10 = 11,600)
  • URL 단축 서비스를 10년간 운영한다고 가정하면 1억 x 365 x 10 = 3650억 개의 레코드를 보관해야 한다.
  • 축약 전 URL의 평균 길이는 100이라고 하자.
  • 따라서 10년 동안 필요한 저장 용량 3650억 x 100바이트 = 36.5TB이다.
위 개략적 추정은 질문을 통해 답변받은 것을 통해서 계산하는 것이며 계산이 끝나면 결과를 면접관과 점검하여 합의한 후에 진행하도록 하자.

 

 

2단계 개략적 설계안 제시 및 동의 구하기

API 엔드포인트

REST API로 설계하는 걸 가정한다.

URL 단축기는 기본적으로 두 개의 엔드포인트를 필요로 한다.

 

1. URL 단축용 엔드포인트

POST /api/v1/data/shorten

  • 인자: { longUrl: longURLstring }
  • 반환: 단축 URL

 

2. URL 리다이렉션용 엔드포인트

GET /api/v1/shortUrl

  • 반환: HTTP 리다이렉션 목적지가 될 원래 URL

 

URL 리다이렉션

다음의 그림은 브라우저에 단축 URL을 입력하면 무슨 일이 생기는지 보여준다.


단축 URL을 받은 서버는 그 URL을 원래 URL로 바꾸어서 301 응답의 Location 헤더에 넣어 반환한다.

다음의 그림은 클라이언트와 서버 사이의 통신 절차를 좀 더 자세히 보여준다.

 

301 응답 VS 302 응답

301 응답과 302 응답 둘 다 리다이렉션 응답이지만, 차이가 있다.

 

301 Permanetly Moved
이 응답은 해당 URL에 대한 HTTP 요청의 처리 책임이 영구적으로 Location 헤더에 반환된 URL로 이전되었다는 응답이다.
영구적으로 이전되었으므로, 브라우저는 이 응답을 캐시 한다.

 

따라서 추후 같은 단축 URL에 요청을 보낼 필요가 있을 때 브라우저는 캐시 된 원래 URL로 요청을 보내게 된다.

 

302 Found
이 응답은 주어진 URL로의 요청이 일시적으로 Location 헤더가 지정하는 URL에 의해 처리되어야 한다는 응답이다.
따라서 클라이언트의 요청은 언제나 단축 URL 서버에 먼저 보내진 후에 원래 URL로 리다이렉션 되어야 한다.

 

이 두 방법은 각기 다른 장단점을 갖고 있다.

서버 부하를 줄이는 것이 중요하다면 `301 Permanent Moved`를 사용하는 것이 좋은데 첫 번째 요청만 단축 URL 서버로 전송될 것이기 때문이다.

 

하지만 트래픽 분석이 중요할 때는 `302 Found`를 쓰는 쪽이 클릭 발생률이나 발생 위치를 추적하는 데 좀 더 유리할 것이다.

URL 리다이렉션을 구현하는 가장 직관적인 방법은 해시 테이블을 사용하는 것이다.

 

해시 테이블에 <단축 URL, 원래 URL>의 쌍을 저장한다고 가정한다면, URL 리다이렉션은 다음과 같이 구현될 수 있을 것이다.

  • 원래 URL = hashTable.get(단축 URL)
  • 301 또는 302 응답 Location 헤더에 원래 URL을 넣은 후 전송

 

URL 단축

단축 URL이 `www.tinyurl.com/{hashValue}` 같은 형태라고 해 보자.
결국 중요한 것은 긴 URL을 이 해시 값으로 대응시킬 해시 함수 fx를 찾는 일이 될 것이다.


이 해시 함수는 다음 요구사항을 만족해야 한다.

  • 입력으로 주어지는 긴 URL이 다른 값이면 해시 값도 달라야 한다.
  • 계산된 해시 값은 원래 입력으로 주어졌던 긴 URL로 복원될 수 있어야 한다.

 

3단계 상세설계

데이터 모델

위에서 언급했듯이 모든 것을 해시 테이블에 두었었다. 이 접근법은 초기 전략으로는 괜찮지만 실제 시스템에 쓰기에는 곤란한데, 메모리는 유한한 데다 비싸기 때문이다.

 

더 나은 방법은 `<단축 URL, 원래 URL>`의 순서쌍을 관계형 데이터베이스에 저장하는 것이다.

 

아래 그림이 테이블의 간단한 설계 사례다.
이 테이블은 단순화된 것으로 `id`, `shortUrl`, `longURL`의 세 개 칼럼을 갖는다.

 

해시 함수

해시 함수는 원래 URL을 단축 URL로 변환하는데 쓰인다. 편의상 해시 함수가 계산하는 단축 URL값을 `hashValue`라고 지칭한다.

 

자릿수 정하기

URL에 담길 수 있는 영역은 숫자와 영문자이다. `([0-9, a-z, A-Z])`

따라서 사용할 수 있는 문자의 개수는 10 + 26 + 26 = 62개이다.

 

우리는 3650억 개의 레코드를 보관할 수 있도록 하는 것을 고려해야 하기 때문에 몇 자리의 문자가 필요한지 계산해 보면 다음과 같다.


따라서 7자리로 3.5조 개의 URL을 커버할 수 있다.
hashValue의 길이는 7로 하면 된다.


해시 함수 구현에 쓰일 기술로는 두 가지 방법을 살펴보자.

하나는 해시 후 충돌 해소 방법이고, 다른 하나는 base-62 변환 법이다.

 

해시 후 충돌 해소

긴 URL을 줄이려면, 원래 URL을 7글자 문자열로 줄이는 해시 함수가 필요하다.
손쉬운 방법은 CRC32, MD5, SHA-1같이 잘 알려진 해시 함수를 이용하는 것이다.

해시 함수 해시 결과 (16진수)
CRC32 5cb54054
MD5 5a62509a84df9ee03fe1230b9dfb84e
SHA-1 0eeae7916c06853901d9ccbefbfcaf4de57ed85b

그런데 위의 표와 같이, CRC32가 계산한 가장 짧은 해시값조차도 7보다는 길다.

어떻게 하면 줄일 수 있을까?

 

이 문제를 해결할 첫 번째 방법은 계산된 해시 값에서 처음 7개 글자만 이용한느 것이다.
하지만 이렇게 하면 해시 결과가 서로 충돌할 확률이 높아진다.
충돌이 실제로 발생했을 때는, 충돌이 해소될 때까지 사전에 정한 문자열을 해시값에 덧붙인다.


이 방법을 쓰면 충돌은 해소할 수 있지만 단축 URL을 생성할 때 한 번 이상 데이터베이스 질의를 해야 하므로 오버헤드가 크다.

데이터베이스 대신 블룸 필터를 사용하면 성능을 높일 수 있다.

 

base-62 변환

진법 변환은 URL 단축기를 구현할 때 흔히 사용되는 접근법 중 하나다.
이 기법은 수의 표현 방식이 다른 두 시스템이 같은 수를 공유하여야 하는 경우에 유용하다.

 

62진법을 쓰는 이유는 hashValue에 사용할 수 있는 문자 개수가 62개이기 때문이다.
`1115710`을 62진수로 변환해 보자.

  • 62진법은 수를 표현하기 위해 62개의 문자를 사용하는 진법이다.
    따라서 0은 0으로 9는 9로, 10은 a로 61은 Z로 대응시켜 표현하도록 할 것이다. 따라서 62진법에서 ‘a’는 10을 나타내고 ‘Z’는 61을 나타낸다.
  • 1115710 = 2 x 622 + 55 X 621 + 59 x 620 = [2, 55, 59] => [2, T, X] => 2 TX62이다.
  • 따라서 단축 URL은 `https://tinyurl.com/2TX`가 된다.

 

두 접근법 비교

해시 후 충돌 해소 전략 base-62 변환
단축 URL의 길이가 고정됨 단축 URL의 길이가 가변적. ID 값이 커지면 같이 길어짐
유일성이 보장되는 ID 생성기가 필요치 않음 유일성 보장 ID 생성기가 필요
충돌이 가능해서 해소 전략이 필요 ID의 유일성이 보장된 후에야 적용 가능한 전략이라 충돌은 아예 불가능
ID로부터 단축 URL을 계산하는 방식이 아니라서 다음에 쓸 수 있는 URL을 알아내는 것이 불가능 ID가 1씩 증가하는 값이라고 가정하면 다음에 쓸 수 있는 단축 URL이 무엇인지 쉽게 알아낼 수 있어서 보안상 문제가 될 소지가 있음

 

URL 단축기 상세 설계

URL 단축기는 시스템의 핵심 컴포넌트이므로, 그 처리 흐름이 논리적으로는 단순해야 하고 기능적으로는 언제나 동작하는 상태로 유지되어야 한다.

본 책에서는 62진법(base62) 변환 기법을 사용해 설계한다.

  1. 입력으로 긴 URL을 받는다.
  2. 데이터베이스에 해당 URL이 있는지 검사한다.
  3. 데이터베이스에 있다면 해당 URL에 대한 단축 URL을 만든 적이 있다는 것이다. 따라서 데이터베이스에서 해당 단축 URL을 가져와서 클라이언트에게 반환한다.
  4. 데이터베이스에 없는 경우에는 해당 URL은 새로 접수된 것이므로 유일한 ID를 생성한다. 이 ID는 데이터베이스의 기본 키로 사용된다.
  5. 62진법 변환을 적용, ID를 단축 URL로 만든다.
  6. ID, 단축 URL, 원래 URL로 새 데이터베이스 레코드를 만든 후 단축 URL을 클라이언트에 전달한다.

 

URL 리다이렉션 상세 설계

쓰기보다 읽기를 더 자주 하는 시스템이라, 캐시에 저장하여 성능을 높였다.


로드밸런서의 동작 흐름은 다음과 같이 요약할 수 있다.

 

  1. 사용자가 단축 URL을 클릭한다.
  2. 로드밸런서가 해당 클릭으로 발생한 요청을 웹 서버에 전달한다.
  3. 단축 URL이 이미 캐시에 있는 경우에는 원래 URL을 바로 꺼내서 클라이언트에게 전달한다.
  4. 캐시에 해당 단축 URL이 없는 경우에는 데이터베이스에서 꺼낸다. 데이터베이스에 없다면 아마 사용자가 잘못된 단축 URL을 입력한 경우일 것이다.
  5. 데이터베이스에서 꺼낸 URL을 캐시에 넣은 후 사용자에게 반환한다.

 

4단계 마무리

설계를 마친 후에도 시간이 좀 남는다면 다음과 같은 것을 면접관과 이야기할 수 있을 것이다.

 

처리율 제한 장치(rate limiter)

  • 지금까지 살펴본 시스템은 엄청난 양의 URL 단축 요청이 있을 경우 무력화될 수 있다는 잠재적 보안 결함을 갖고 있다. 처리율 제한 장치를 두면, IP 주소를 비롯한 필터링 규칙들을 이용해 요청을 걸러낼 수 있을 것이다.

 

웹 서버의 규모 확장

  • 본 설계에 포함된 웹 계층은 무상태 계층이므로, 웹 서버를 자유롭게 증설하거나 삭제할 수 있다.

 

데이터베이스의 규모 확장

  • 데이터베이스를 다중화하거나 샤딩(sharding)하여 규모 확장성을 달성할 수 있다.

 

데이터 분석 솔루션(analytics)

  • 성공적인 비즈니스를 위해서는 데이터가 중요하다. URL 단축기에 데이터 분석 솔루션을 통합해 두면 어떤 링크를 얼마나 많은 사용자가 클릭했는지, 언제 주로 클릭했는지 등 중요한 정보를 알아낼 수 있을 것이다.

 

가용성, 데이터 일관성, 안정성

  • 대규모 시스템이 성공적으로 운영되기 위해서는 반드시 갖추어야 할 속성들이다.

 

 

+ 회고 시 스터디원들과 나눴던 내용들

단축 URL을 빠르게 찾기 위해서 캐시를 사용하지만 캐시에 없다면 RDB에서 찾아야 하는데 읽기 성능이 중요할 거 같은데 mongodb 같은 nosql 사용은 어떻게 생각하시나요?

단축 URL 시스템에서 대부분의 요청은 캐시(예: Redis, Memcached)를 통해 빠르게 처리되지만,

캐시에 없는 경우에는 결국 데이터베이스에서 원본 URL을 찾아야 한다.


초당만 건 이상의 읽기 요청과 수십~수백억 건의 레코드를 고려할 때, 데이터베이스의 읽기 성능과 확장성이 굉장히 중요한 요소가 된다.

RDB도 인덱싱과 리드 레플리카를 통해 어느 정도까지는 성능을 낼 수 있지만,

데이터가 수십 테라바이트 규모로 커지면 샤딩 및 분산 처리가 필요해지고, 운영 복잡성이 급격히 높아진다.

또한 키-값 단순 조회 패턴에서는 관계형의 고도 기능(조인, 트랜잭션 등)이 거의 필요하지 않기 때문에,

이럴 때는 MongoDB 같은 NoSQL이 훨씬 적합한 선택이 될 수 있다.

 

What database to use for URL Shortener project

 

유명한 서비스나 오픈소스가 있는지

The 7 best URL shortener services

 

왜 대규모 시스템에서 URL을 단축해야 할까요?

서두에 서술!

 

 

 

 

출처
https://jonghoonpark.com/2023/06/15/url-shortener
직접 구현해 보는 URL 단축기

저작자표시 비영리 (새창열림)

'📝 끄적끄적 > 📖 가상 면접 사례로 배우는 대규모 시스템 설계 기초' 카테고리의 다른 글

9장. 웹 크롤러 설계  (0) 2025.07.14
7장. 분산 시스템을 위한 유일 ID 생성기 설계  (0) 2025.07.01
6장. 키-값 저장소 설계  (0) 2025.07.01
5장. 안정 해시 설계  (0) 2025.06.30
4장. 처리율 제한 장치의 설계  (0) 2025.06.30
3장. 시스템 설계 면접 공략법  (0) 2025.06.05
'📝 끄적끄적/📖 가상 면접 사례로 배우는 대규모 시스템 설계 기초' 카테고리의 다른 글
  • 9장. 웹 크롤러 설계
  • 7장. 분산 시스템을 위한 유일 ID 생성기 설계
  • 6장. 키-값 저장소 설계
  • 5장. 안정 해시 설계
현주먹
현주먹
대구 불주먹 출신 현주먹의 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (179)
      • 👶🏻 CS (15)
        • Operating System (7)
        • DB (5)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • DB&JPA (6)
        • Test Code (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (74)
        • 후기 및 회고 (11)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
        • 📖 가상 면접 사례로 배우는 대규모 시스템 설계 .. (11)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL repository
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    오블완
    에프랩
    코딩테스트준비
    자바의정석
    인프런 특정문자뒤집기
    에프랩 후기
    티스토리챌린지
    jsp
    F-Lab
    JPA
    백준
    99클럽
    ==와 equals()
    개구리책
    TDD 클린 코드 with Java
    C
    항해99
    객체지향
    til
    코테스터디
    오라클
    로또 미션
    f-lab 후기
    jsp 2.3 웹 프로그래밍: 기초부터 중급까지
    NextSTEP
    개발자취업
    자바의신절판
    데브클럽
    개발자멘토링
    2025스프링캠프
  • hELLO· Designed By정상우.v4.10.2
현주먹
8장. URL 단축기 설계
상단으로

티스토리툴바