Understand it step by step (한국어로 이해 → 영어로 말하기)
- 1
기능 요구사항은 딱 2개다. (1) 긴 URL을 받아 짧은 코드를 돌려준다. (2) 짧은 코드로 오면 원래 URL로 301/302 리다이렉트한다. 선택으로 커스텀 별칭(alias)과 만료(TTL), 클릭 수 집계.
🔧 도구:301 (permanent)302 (temporary)
🗣 영어로 말해“Two core features: shorten a long URL into a code, and redirect a code back to the original.”
checking microphone…
- 2
비기능 요구사항: 리다이렉트는 매우 빨라야 한다(p99 ~50ms 미만). 읽기가 쓰기보다 훨씬 많다(약 100:1). 일관성보다 가용성을 택한다 — 링크는 항상 열려야 하고, 새로 만든 링크가 1~2초 늦게 퍼져도 괜찮다. 한 번 만든 코드는 절대 다른 URL로 바뀌면 안 된다(불변).
⚖️ Trade-off: 강한 일관성을 포기하고 가용성을 택한다. 새 링크가 잠깐 안 보이는 건 참지만, 리다이렉트가 죽는 건 안 된다.
🔧 도구:availability over consistencyimmutable mapping
🗣 영어로 말해“Reads dominate writes about 100 to 1, so I optimize for fast, highly available redirects.”
checking microphone…
- 3
스케일 추정: 하루 1억 개 새 링크 생성이면 쓰기 약 1,000 QPS. 읽기는 100배라 약 100,000 QPS(피크는 2~3배). 링크 하나당 약 500바이트, 5년이면 1억x365x5 ≈ 1,800억 행, 약 90TB. 한 대 DB로는 절대 안 되니 샤딩이 전제다.
🔧 도구:1B-scale rows~90TBsharding required
🗣 영어로 말해“Roughly a thousand writes and a hundred thousand reads per second, so a single DB won't fit.”
checking microphone…
- 4
API는 단순하다. 생성은 POST /urls 에 longUrl을 보내면 shortCode를 받는다. 리다이렉트는 GET /{code}. 데이터 모델은 사실상 키-값 한 장: code가 파티션 키, 그 안에 longUrl, createdAt, expireAt, 만든 사람. code로만 조회하므로 RDB의 인덱스보다 키-값 분산 저장소가 자연스럽다.
🔧 도구:DynamoDBCassandrakey-value store
POST /urls { "longUrl": "...", "alias?": "...", "ttl?": 86400 } -> 201 { "shortCode": "aZ8kQp" } GET /{code} -> 302 Location: <longUrl> // table (DynamoDB / Cassandra) // PK: code (string, 7 chars) <- only access pattern // longUrl, createdAt, expireAt(TTL), ownerId🗣 영어로 말해“It's basically one key-value table: short code is the partition key, value is the long URL.”
checking microphone…
- 5
상위 설계: 클라이언트 → CDN/로드밸런서 → 짧은 서비스(stateless, 여러 대). 읽기 경로는 서비스가 먼저 Redis 캐시를 보고(핫 링크 90%+가 여기서 끝남), 없으면 키-값 DB에서 읽고 캐시에 채운 뒤 302를 돌려준다. 쓰기 경로는 코드를 발급해 DB에 한 줄 쓴다. 클릭 집계는 응답 경로를 막지 않게 Kafka로 비동기로 흘려 워커가 따로 센다.
🔧 도구:CDNRedisKafkaasync workersstateless service
🗣 영어로 말해“Read path hits Redis first, falls back to the DB, and clicks go async through Kafka.”
checking microphone…
- 6
딥다이브 1 — 코드를 어떻게 안 겹치게 만드나? 핵심 어려운 부분이다. 후보 3개를 비교한다. ① 긴 URL을 해시(MD5)해서 앞 7자 → 충돌이 나서 충돌 처리가 필요. ② DB auto-increment ID를 base62로 인코딩 → 충돌은 없지만 ID가 순차라 다음 코드를 예측당하고, 단일 카운터가 병목. ③ 중앙 ID 발급기가 1,000개씩 ID 구간(range)을 각 서버에 미리 떼어주고, 서버는 그 안에서 로컬로 base62 인코딩 → 충돌 없음, DB 왕복 거의 없음, 서버 추가도 쉬움. 그래서 ③을 택한다.
⚖️ Trade-off: 랜덤이 아니라 구간 기반이라 코드 순서에 약한 패턴이 생긴다. 추측 방지가 중요하면 구간 안에서 순서를 섞거나 랜덤 7자 + 충돌 재시도로 바꾼다.
✅ Fix: 62진법(a-z A-Z 0-9) 7자리면 62^7 ≈ 3.5조 개라 5년치 1,800억 개를 충분히 덮는다. 발급기가 구간을 미리 떼어주니 코드 생성에 DB 락도, 매번 왕복도 필요 없다.
🔧 도구:base62Snowflake / ID allocatorranged ID leasingZookeeper/DB sequence
// base62: 7 chars = 62^7 ~= 3.5 trillion codes String encode(long id) { /* id -> [a-zA-Z0-9]{7} */ } // each server leases a range, no per-write DB round-trip range = idAllocator.lease(1000); // e.g. [4_000_000, 4_001_000) code = encode(range.next()); // local, no lock🗣 영어로 말해“I hand each server a pre-allocated range of IDs, then base62-encode locally, so codes never collide.”
checking microphone…
- 7
딥다이브 2 — 핫 키와 읽기 폭발. 한 링크가 갑자기 바이럴되면(예: 광고 링크) 그 code 하나에 초당 수만 요청이 한 캐시 노드로 몰린다. 매핑은 불변이라 캐시 TTL을 길게(시간 단위) 잡아도 안전하고, CDN 엣지에서 302를 캐시해 원본 서버까지 안 오게 한다. 캐시가 비는 순간 동시에 DB로 몰리는 캐시 스탬피드는 single-flight(키별로 한 요청만 DB를 채우고 나머지는 그 결과를 기다림)로 막는다.
⚖️ Trade-off: 엣지 캐시 TTL이 길면 삭제/만료된 링크가 잠깐 더 살아 있을 수 있다. 그건 짧은 TTL의 무효화 신호나 만료 체크로 받아들인다.
✅ Fix: 불변이라는 성질이 무기다. 캐시 무효화를 신경 쓸 필요가 없어 TTL을 길게 잡고, 핫 키는 엣지에서 끝내고, 콜드 스타트 순간만 single-flight로 한 번만 DB를 읽는다.
🔧 도구:CDN edge cachesingle-flightlong TTL (immutable)consistent hashing
🗣 영어로 말해“Mappings are immutable, so I cache aggressively at the CDN edge and use single-flight on misses.”
checking microphone…
- 8
트레이드오프 + 모니터링: 가용성을 위해 강한 일관성을 포기했다 — 새 링크가 모든 리전에 퍼지기까지 1~2초 지연이 있다. 또 클릭 집계는 비동기라 실시간이 아니라 약간 늦다. 모니터링은 리다이렉트 p99 지연, 캐시 적중률(목표 90%+), DB 샤드별 QPS와 핫 샤드 쏠림, ID 구간 소진 속도, 5xx 비율, Kafka 컨슈머 랙을 본다.
⚖️ Trade-off: 강한 일관성과 실시간 정확한 클릭 수를 포기하고, 항상 빠르게 열리는 링크를 얻었다. 읽기 위주 서비스에선 맞는 교환이다.
🔧 도구:cache hit ratep99 latencyshard QPS skewKafka consumer lag
🗣 영어로 말해“I gave up strong consistency for availability, and I watch redirect p99, cache hit rate, and hot shards.”
checking microphone…
8단계 영어를 다 말하면 → 이 메커니즘 전체를 영어로 설명할 수 있게 된다.