Skip to content

Commit e7e2acc

Browse files
authored
Merge pull request #5 from System-Deep-Dive/feat/#4
초기 Design Doc 작성
2 parents a35a5e2 + 7dccf52 commit e7e2acc

3 files changed

Lines changed: 149 additions & 348 deletions

File tree

README.md

Lines changed: 149 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,149 @@
1-
# Bitly-Jungeun
1+
## Design Doc: 빠른 리다이렉트가 가능한 URL 단축기
2+
3+
본 문서는 구글식 디자인 문서 구조를 참고하여(URL 단축기의) 리다이렉트 경로를 초저지연으로 만드는 설계를 요약합니다.
4+
5+
### 1. Context & Scope
6+
- 문제 배경: URL 단축기는 극단적인 읽기 중심 워크로드를 갖습니다. 수백만~수억 건의 리다이렉트 트래픽에서 p95/p99 지연을 낮추는 것이 핵심입니다.
7+
- 현재 가정 트래픽: 1억 DAU × 5회/일 ≈ 5억/일 → 평균 ~5,787 RPS, 피크 100× 가정 시 ~60만 RPS.
8+
- 스코프: 단축 코드 → 원본 URL 매핑 조회 경로 최적화(데이터 레이어 및 엣지)
9+
- 비스코프: 단축 URL 생성 알고리즘의 상세(충돌 방지, 키 공간 설계 등)는 별도 문서에서 다룸.
10+
11+
### 2. Goals / Non-Goals
12+
- Goals
13+
- p95 리다이렉트 지연 단자리 ms(지역/엣지 히트 시)를 목표
14+
- 피크 시 ~60만 RPS 리다이렉트 처리 가능
15+
- 고가용성: 단일 장애 지점 제거, 캐시/DB/엣지 이중화
16+
- 캐시 히트율 90%+ (핫 코드 기준), 오리진 도달율 최소화
17+
- Non-Goals
18+
- 단축 URL 생성 파이프라인 최적화
19+
- 광고/과금 로직 최적화
20+
- 정교한 AB 테스트/퍼스널라이제이션
21+
22+
### 3. System Context Diagram (고수준)
23+
- 사용자는 `https://sho.rt/{code}` 로 접속
24+
- CDN(전세계 PoP) → 엣지 함수(코드 조회) →
25+
- 엣지 캐시 hit 시: 301/302 즉시 응답
26+
- miss 시: 오리진 API → Redis →(miss)→ DB 조회 후 응답 및 상위 캐시 적재
27+
- 관측(로그/메트릭/트레이싱)은 엣지/오리진 모두에서 수집
28+
29+
### 4. APIs (스케치)
30+
- GET `/{code}`: 코드로 리다이렉트 수행
31+
- 301/302 Location: `<original_url>`
32+
- 캐시 제어 헤더: 엣지 캐시 가능, 단 TTL/무효화 정책 고려
33+
- POST `/shorten` (참고): 원본 URL → 단축 코드 생성(본 문서 비스코프)
34+
35+
### 5. Data Storage
36+
- 테이블: `url_mapping`
37+
- `code` (PK, 고정 길이 문자열) — 단축 코드, 기본 키 및 인덱스
38+
- `original_url` (text)
39+
- `created_at`, `expires_at`(선택)
40+
- 인덱싱
41+
- B-트리 인덱스(기본) 또는 해시 인덱스(정확 일치 최적화, PostgreSQL 등)
42+
- 샤딩/파티셔닝: 코드 해시 기반 범용 샤딩, 리전별 리드 레플리카
43+
44+
### 6. Design
45+
- 6.1 읽기 경로 레이어링
46+
- 엣지 캐시(및 엣지 키-밸류 저장) → 오리진 Redis/Memcached → RDBMS
47+
- 캐시 키: `url:{code}` → value: `<original_url>`
48+
- TTL: 인기 코드 장기 캐시, 비인기 코드 짧은 TTL 또는 캐시 미적재
49+
50+
- 엣지(Cloudflare Workers, Lambda@Edge)
51+
- 인기 코드 즉시 리다이렉트, 오리진 경유 차단
52+
- 캐시 무효화: 관리용 API 또는 tag 기반 purge
53+
54+
- 오리진(애플리케이션)
55+
- 캐시 미스 시 Redis 조회, 다시 미스면 DB 조회 후 301/302
56+
- 결과를 Redis 및 엣지에 업서트(upsert)
57+
58+
- 6.2 캐시 정책
59+
- 에비션: LRU 우선, 크기 제한 엄수
60+
- TTL: 트래픽 기반 가변 TTL(핫 키는 길게)
61+
- 프리워밍: 롤아웃 전 상위 N개 인기 코드 프리로드
62+
63+
- 6.3 일관성/무효화
64+
- 대부분 read-only. 삭제/만료/수정 이벤트 시
65+
- 오리진에서 Redis/엣지에 무효화 브로드캐스트
66+
- 지연 허용 시 TTL 자연 만료
67+
68+
### 7. Alternatives Considered
69+
- 단일 DB만으로 버티기
70+
- 장점: 단순. 단일 신뢰 경로
71+
- 단점: 초고 RPS 피크 처리 어려움, 스케일/비용 한계
72+
- CDN만 사용(오리진 캐시 미활용)
73+
- 장점: 사용자는 빠름(히트 시)
74+
- 단점: 글로벌 무효화/미스 처리 비용 증가, 오리진 병목 발생
75+
- NoSQL(예: DynamoDB) 단독
76+
- 장점: 키-밸류 조회에 적합, 수평 확장
77+
- 단점: 기존 RDB 스키마/관계 활용 어려움, 마이그레이션 비용
78+
79+
### 8. Cross-Cutting Concerns
80+
- 보안: 개방 리다이렉트 방지(허용 도메인 검증), 악용 방지 레이트 리밋
81+
- 프라이버시: 쿼리 파라미터/PII 로깅 최소화, 지역 규제 준수
82+
- 관측성: RPS, p50/95/99, 히트율, 오리진 도달율, 4xx/5xx, 엣지/오리진 트레이싱
83+
- 신뢰성: 멀티 리전, 다중 캐시 노드, 캐시 장애 시 페일오버 경로 확인
84+
- 비용: CDN/엣지/캐시/DB 별 단가 모니터링, 인기 키 집중 최적화
85+
86+
### 9. Rollout Plan
87+
- 단계 1: DB 인덱싱/샤딩 정비, 읽기용 레플리카 확충
88+
- 단계 2: 오리진 Redis 도입, 캐시 키/TTL 설계, 프리워밍
89+
- 단계 3: CDN/엣지 함수 배포, 인기 코드 엣지 캐시
90+
- 단계 4: 글로벌 무효화/태그 purge 자동화, 히트율/지연 최적화 반복
91+
92+
### 10. Metrics & SLO
93+
- SLO: p95 리다이렉트 < 50ms(리전 내), 가용성 ≥ 99.95%
94+
- 핵심 지표: 캐시 히트율, 오리진 도달율, 엣지/오리진 p95/99, 에러율, 비용/요청
95+
96+
### 11. Risks & Mitigations
97+
- 글로벌 캐시 불일치 → TTL/태그 purge, 변경 이벤트 브로드캐스트
98+
- 엣지 제한(메모리/런타임) → 경량 로직, 키 압축, 외부 의존 최소화
99+
- 핫 키 쏠림 → 레이트 리밋/스티키 캐시, 다중 리전 분산
100+
101+
### 12. Open Questions
102+
- 만료 정책: per-code TTL vs 글로벌 TTL 최적 조합?
103+
- 멀티 테넌트/도메인 지원 시 키 스키마 확장 방안?
104+
- 퍼스널라이즈드 리다이렉트(기기/지역별) 요구가 생길 경우 엣지 로직 분기 전략?
105+
106+
### 13. References
107+
- Google 스타일 디자인 문서 개요 정리: GN 기사 요약 참고 (https://news.hada.io/topic?id=14704)
108+
109+
110+
## Local Dev Setup (Docker Compose)
111+
112+
### Prerequisites
113+
- Docker Desktop (Compose v2)
114+
115+
### Services
116+
- PostgreSQL 16, Redis 7(alpine). Spring Boot 앱은 추후 `api` 서비스로 추가 예정.
117+
118+
### Memory Limits in Compose
119+
- `deploy.resources.limits.memory`는 Swarm 용 필드입니다. 로컬 Compose에서 강제하려면 `docker compose --compatibility up` 또는 서비스별 `mem_limit`(레거시) 사용을 권장합니다.
120+
- JVM(스프링) 컨테이너는 `-XX:+UseContainerSupport -XX:MaxRAMPercentage=<N>`로 컨테이너 메모리 한도를 인지시켜야 OOM을 피할 수 있습니다.
121+
122+
### How to Run
123+
```bash
124+
docker compose --compatibility up -d
125+
```
126+
127+
### Connection Info
128+
- Postgres: `localhost:5432` (user: bitly, password: bitly, db: bitly)
129+
- Redis: `localhost:6379`
130+
131+
### Spring Boot (예시 설정)
132+
- `application.yml` 예시
133+
```yaml
134+
spring:
135+
datasource:
136+
url: jdbc:postgresql://postgres:5432/bitly
137+
username: bitly
138+
password: bitly
139+
redis:
140+
host: redis
141+
port: 6379
142+
server:
143+
port: 8080
144+
```
145+
146+
### Notes
147+
- Redis는 `--maxmemory 1gb --maxmemory-policy allkeys-lru`로 설정되어 LRU 에비션 동작.
148+
- Postgres/Redis 모두 healthcheck 포함.
149+
- 추후 엣지/CDN 적용 시, 인기 코드 Top-N 프리워밍과 태그 기반 purge 전략을 고려하세요.

TestJavaClass.java

Lines changed: 0 additions & 205 deletions
This file was deleted.

0 commit comments

Comments
 (0)