이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- System Design 사례 답안을 어떤 순서로 리뷰해야 하는가?
- 컴포넌트가 많은 설계와 운영 가능한 설계를 어떻게 구분하는가?
- 설계 리뷰는 성능, 정합성, 장애 격리, 운영 복잡도 중 무엇을 검증해야 하는가?
개요
설계 리뷰는 답안의 그림을 평가하는 일이 아니다. 요구사항이 구조 선택으로 연결되었는지, 병목과 실패 모델이 드러났는지, 운영자가 볼 지표가 있는지 확인하는 일이다. URL Shortener, Notification, Chat, Feed는 모두 cache, queue, DB를 쓸 수 있다. 하지만 각 사례에서 그 컴포넌트가 해결하는 문제는 다르다. 리뷰는 “Kafka가 있나”가 아니라 “왜 비동기 경계가 필요하고 실패하면 어떻게 복구하는가”를 묻는다.
이 문서가 바꾸는 설계 축
| 축 | 리뷰 질문 |
|---|---|
| 성능 | 핵심 경로의 p95, QPS, fanout, cache hit 계산이 있는가? |
| 정합성 | unique, ordering, idempotency, stale 허용 범위가 명시되는가? |
| 장애 격리 | 핵심 경로와 부가 경로가 분리되고 degrade 기준이 있는가? |
| 운영 복잡도 | 지표, alert, DLQ, replay, migration, owner가 정의되는가? |
리뷰 순서
설계안을 볼 때는 다음 순서로 읽는다.
- 사용자 성공 기준을 확인한다.
- 기능 요구사항과 비기능 요구사항을 분리한다.
- read/write 비율과 peak를 확인한다.
- 핵심 동기 경로를 짧게 만든다.
- 비동기 경계의 중복과 지연을 확인한다.
- 상태 owner와 최종 진실의 원천을 찾는다.
- 장애 때 포기할 기능을 정한다.
- 운영 지표와 runbook을 붙인다. 이 순서를 따르면 그림이 화려해도 근거가 없는 설계를 걸러낼 수 있다.
사례별 핵심 질문
| 사례 | 반드시 물어야 할 질문 |
|---|---|
| URL Shortener | redirect p95와 cache miss 때 DB 보호는 어떻게 하는가? |
| Notification | 수신 거부, provider 실패, 중복 발송을 어떻게 처리하는가? |
| Chat | 메시지 저장 성공과 실시간 전달 실패를 어떻게 복구하는가? |
| Feed | follower skew와 유명인 계정 fanout을 어떻게 제한하는가? |
| 질문이 사례별로 달라야 한다. | |
| 같은 질문표를 모든 사례에 붙이면 실제 설계 판단이 사라진다. |
나쁜 답안 예시
다음 답안은 겉으로는 그럴듯하다.
Client -> API Gateway -> Service -> Redis -> DB -> Kafka -> Worker하지만 다음 질문에 답하지 못하면 부족하다.
- Redis에는 무엇이 들어가고 TTL은 왜 그 값인가?
- DB가 최종 진실의 원천인 데이터는 무엇인가?
- Kafka message가 중복되면 어떤 side effect가 생기는가?
- Worker가 1시간 밀리면 사용자는 무엇을 보는가?
- 장애 때 어떤 기능을 끄고 어떤 기능을 유지하는가? 컴포넌트 이름은 설계의 결론이 아니라 질문을 시작하는 단서다.
요구사항 누락 찾기
기능 요구사항이 너무 짧으면 설계가 흔들린다.
| 빠진 요구사항 | 나중에 생기는 문제 |
|---|---|
| 데이터 보존 기간 | storage와 삭제 정책 부재 |
| 중복 허용 범위 | idempotency 누락 |
| 지연 허용 범위 | sync/async 경계 오류 |
| 사용자 차단/삭제 | materialized data 정리 누락 |
| 관리자/운영 기능 | 장애 중 원인 확인 불가 |
| abuse/rate limit | 비용과 보안 위험 증가 |
| 리뷰어는 “이 기능도 필요하지 않나”가 아니라 “이 요구가 없으면 어떤 구조 선택을 못 하는가”를 지적해야 한다. |
트래픽 계산 검토
계산은 정확한 예측보다 구조 선택의 근거다.
redirect_qps = 25,000
cache_hit = 98%
db_fallback_qps = 500
notification_targets = 5,000,000
send_window = 2h
required_send_rate = 695 msg/s
chat_room_size = 10,000
messages_per_second = 100
deliveries_per_second = 1,000,000계산이 있으면 cache, queue, provider quota, fanout 전략이 왜 필요한지 설명할 수 있다. 계산이 없으면 컴포넌트 선택이 취향이 된다.
상태 owner 검토
상태마다 owner를 하나로 정한다.
| 상태 | owner 예시 | 리뷰 포인트 |
|---|---|---|
| short URL mapping | URL DB | key uniqueness와 만료 |
| delivery status | Notification service | retry와 DLQ |
| chat message | Message store | ordering과 replay |
| presence | Redis TTL | stale 허용 |
| timeline item | Feed store | rebuild와 삭제 반영 |
| Owner가 둘 이상이면 충돌 해결 기준을 반드시 물어야 한다. | ||
| Owner가 없으면 장애 후 복구 기준도 없다. |
실패 모델 검토
좋은 설계는 실패를 숨기지 않는다.
| 실패 | 물어볼 것 |
|---|---|
| cache down | DB fallback을 허용할 수 있는가? |
| queue lag | 사용자에게 지연을 보여줄 것인가? |
| provider 429 | retry를 늦출 것인가, 발송을 포기할 것인가? |
| worker bug | replay할 수 있는가? |
| partial write | idempotency와 reconciliation이 있는가? |
| hot key | key별 rate limit이나 별도 path가 있는가? |
| “장애가 나면 재시도한다”는 답은 부족하다. | |
| 무엇을 언제까지 재시도하고, 언제 DLQ나 degrade로 바꿀지 필요하다. |
API 계약 검토
API 응답은 상태를 숨기지 않아야 한다.
{
"requestId": "notif-777",
"status": "ACCEPTED",
"estimatedDelaySeconds": 30
}{
"messageId": "msg-100",
"roomSequence": 9912,
"delivery": "STORED"
}비동기 시스템에서 200 OK만 반환하면 사용자는 완료로 오해할 수 있다.
접수, 저장, 발송, 전달, 읽음은 서로 다른 상태다.
개선 제안 방식
리뷰 코멘트는 기술 이름을 추가하는 방식보다 trade-off를 드러내야 한다.
| 약한 코멘트 | 나은 코멘트 |
|---|---|
| Redis를 넣자 | redirect DB fallback을 500 QPS 이하로 유지하려면 Redis cache hit 98%가 필요하다. |
| Kafka를 쓰자 | 알림 provider 장애가 주문 API를 막지 않도록 발송 요청을 queue로 분리하고 DLQ를 둔다. |
| Sharding하자 | feed timeline write가 celebrity follower 수만큼 증폭되므로 celebrity path를 분리한다. |
| 모니터링하자 | fanout queue oldest age가 30초를 넘으면 freshness SLO 위반으로 본다. |
| 좋은 리뷰는 선택 이유와 실패 비용을 함께 말한다. |
개인 프로젝트 기준
- 설계 그림 옆에 요구사항 표와 핵심 계산을 붙인다.
- 각 컴포넌트가 없으면 무엇이 깨지는지 한 문장으로 설명한다.
- cache, queue, DB 중 최종 진실의 원천을 표시한다.
- 장애 시나리오 3개와 대응을 적는다.
- “생략한 것”과 “나중에 전환할 조건”을 명시한다.
기업 운영 기준
- 설계 리뷰 문서에는 owner, SLO, alert, rollback, migration, cost가 들어간다.
- dependency별 timeout과 retry budget을 확인한다.
- DLQ, replay, backfill, rebuild는 담당자와 runbook을 가진다.
- 데이터 삭제/차단/수신 거부 같은 정책 요구를 구조에 반영한다.
- 출시 후 실제 지표로 설계 가정을 갱신한다.
위험 신호
- 모든 사례가 같은 아키텍처 그림으로 설명된다.
- QPS와 fanout 계산 없이 cache와 queue를 넣는다.
- API 응답이 비동기 상태를 숨긴다.
- DLQ가 있지만 재처리 기준과 idempotency가 없다.
- 상태 owner 없이 여러 service가 같은 데이터를 수정한다.
- 운영 지표가 기술 지표만 있고 사용자 영향 지표가 없다.
확인 질문
확인 질문
- 확인 질문: 설계 리뷰에서 가장 먼저 볼 것은 무엇인가?
- 답변: 사용자가 성공으로 기대하는 결과와 그 결과를 보장하기 위한 핵심 경로다.
- 확인 질문: 컴포넌트가 많은 설계가 항상 좋은 설계가 아닌 이유는 무엇인가?
- 답변: 각 컴포넌트가 해결하는 요구사항과 새로 만드는 실패 비용이 설명되지 않으면 복잡도만 늘어나기 때문이다.
- 확인 질문: 좋은 개선 제안은 어떤 형태인가?
- 답변: 기술 이름이 아니라 지표, 선택 이유, trade-off, 장애 시 대응 기준을 함께 제시하는 형태다.