본문으로 바로가기

42

시스템 설계 면접 6단계 방법

백지 앞에서 얼어붙지 않는 법 — 무엇을 어떤 순서로 물을 것인가

먼저 보면 좋은 강의: 웹 요청의 해부, 지연 시간과 처리량

단계별로 보기

스페이스바로 재생/정지, 좌우 화살표로 단계 이동, R로 처음으로 돌아갑니다.

대기 중1 / 4 단계 — 1·2단계 — 무엇을, 얼마나

아직 아무것도 그리지 않았습니다. 먼저 묻습니다. 무엇을 만듭니까. 긴 주소를 짧게 만들고, 짧은 주소를 누르면 원래대로 보낸다. 통계와 계정은 범위 밖. 그리고 숫자를 셉니다. 쓰기 초당 12건, 읽기 초당 1200건. 읽기가 쓰기의 100배. 이 비율 하나가 앞으로의 모든 결정을 지배합니다. 숫자를 세지 않고 부품을 고르면, 그건 설계가 아니라 취향입니다.

유입 요청초당 1,200건

이 강의를 마치면

  • 설계 문제를 6단계의 정해진 순서로 분해해서 접근한다.
  • 설계를 시작하기 전에 반드시 범위를 좁히고 숫자를 세워야 하는 이유를 설명한다.
  • '정답'이 아니라 '근거 있는 선택과 그 대가'를 말하는 것이 설계임을 설명한다.
  • URL 단축 서비스 예제에 6단계를 처음부터 끝까지 적용한다.

백지의 공포

"트위터를 설계해 보세요."

이 말을 들으면 대부분 두 가지 중 하나를 합니다. 얼어붙거나, 아니면 곧바로 "일단 로드밸런서를 두고 서버를 여러 대…"라고 부품 이름을 나열하기 시작합니다.

둘 다 실패합니다. 후자가 더 나빠 보이지 않지만 사실 더 나쁩니다. 무엇을 만드는지도 모르면서 부품부터 고르고 있기 때문입니다.

설계는 재능이 아니라 순서입니다. 이 강의는 그 순서를 드립니다. 이 순서는 면접장에서만 쓰는 게 아닙니다. 실제로 새 시스템을 만들 때 쓰는 순서와 같습니다.

1. 요구사항 명확화   — 무엇을 만드는가
2. 규모 추정         — 얼마나 크게 만드는가
3. API와 데이터 모델 — 겉과 속의 계약
4. 상위 설계         — 큰 그림
5. 병목 심화         — 가장 먼저 무너질 곳
6. 트레이드오프      — 무엇을 포기했는가

---

1단계 — 요구사항 명확화

절대로 바로 그리지 마세요. 먼저 물어야 합니다.

"트위터를 설계하라"는 요구는 사실 요구가 아닙니다. 트위터에는 타임라인, 검색, DM, 알림, 광고, 추천이 다 있습니다. 이걸 다 하면 아무것도 못 합니다.

물어야 할 것은 세 가지입니다.

  • 무엇을 하는가 (기능) — 이 중 어디까지가 범위입니까? 글쓰기와 피드 읽기만

할까요?

  • 어때야 하는가 (품질) — 얼마나 빨라야 합니까? 얼마나 안 죽어야 합니까?

데이터가 잠깐 안 맞아도 괜찮습니까?

  • 무엇을 안 하는가 (범위 밖) — 이번엔 검색과 광고는 다루지 않겠습니다.

마지막 항목이 특히 중요합니다. 범위를 명시적으로 잘라내지 않으면 나중에 반드시 "그럼 검색은요?"라는 질문에 무너집니다. 미리 "이번 범위 밖입니다"라고 말해두면 그 질문 자체가 사라집니다.

이 단계에서 가장 흔한 실수: 물어보지 않는 것. 묻지 않고 시작하면, 상대가 생각한 것과 다른 걸 30분간 설계하게 됩니다.

2단계 — 규모 추정

이제 숫자를 셉니다. 이 단계가 없으면 나머지 전부가 취향 문제로 전락합니다.

"캐시를 두겠습니다"라는 말은 숫자가 없으면 그냥 유행어입니다. "읽기가 초당 150건인데 데이터베이스는 30건뿐이라 캐시가 필요합니다"는 근거입니다.

세는 방법은 단순합니다. 사용자 수에서 시작해 초당 몇 건인지까지 내려갑니다.

숫자는 정확할 필요가 전혀 없습니다. 자릿수만 맞으면 됩니다. 초당 100건과 초당 10만 건은 완전히 다른 설계지만, 초당 100건과 초당 130건은 같은 설계입니다.

꼭 세야 할 것은 세 가지입니다.

  • 초당 요청 수 — 그리고 읽기와 쓰기를 반드시 나눠서. 이 비율이

설계의 절반을 결정합니다.

  • 최대치 — 평균의 2~5배로 잡습니다. 시스템은 평균이 아니라 최대치에서

무너집니다.

  • 저장 용량 — 하루에 얼마나 쌓이고, 몇 년을 보관해야 하는가.

3단계 — API와 데이터 모델

큰 그림을 그리기 전에 계약을 정합니다.

API는 바깥과의 계약입니다. 무엇을 받아서 무엇을 돌려주는가. 두세 줄이면 충분합니다.

POST /urls        {긴 주소} → {짧은 주소}
GET  /{짧은코드}   → 원래 주소로 이동

데이터 모델은 안쪽의 계약입니다. 무엇을 어떤 모양으로 저장하는가.

이 단계를 건너뛰는 사람이 많은데, 여기서 나오는 정보가 결정적입니다. 위 API를 보면 읽기(GET)가 쓰기(POST)보다 압도적으로 많을 것임이 바로 드러납니다. 짧은 주소는 한 번 만들고 수천 번 눌리니까요. 이 사실 하나가 4단계의 구조를 거의 결정합니다.

4단계 — 상위 설계

이제야 그림을 그립니다. 앞의 세 단계가 있어야 이 그림의 모든 선에 이유가 생깁니다.

요령은 가장 단순한 것부터 그리고, 숫자가 강제할 때만 부품을 더하는 것입니다.

사용자 → 서버 → 데이터베이스

여기서 시작합니다. 그리고 2단계의 숫자를 하나씩 대봅니다.

  • "초당 150건인데 서버 하나가 40건이네" → 로드밸런서 + 서버 여러 대
  • "데이터베이스는 30건뿐인데 읽기가 150건이네" → 앞에 캐시
  • "이 작업은 사용자를 기다리게 할 이유가 없네" → 큐 + 워커로 뒤로 뺀다

부품마다 그것을 강제한 숫자를 말할 수 있어야 합니다. 말할 수 없는 부품은 빼세요. 그건 장식입니다.

5단계 — 병목 심화

그림이 나왔습니다. 이제 가장 먼저 무너질 곳 하나를 골라 깊이 팝니다.

전부를 깊게 파려 하면 아무것도 못 팝니다. 하나를 고르세요.

고르는 기준은 "가장 어려운 곳"이 아니라 "제일 먼저 터질 곳"입니다. 보통은 이 셋 중 하나입니다.

  • 가장 느린 부품 — 대개 데이터베이스
  • 혼자뿐인 부품 — 죽으면 전체가 죽는 곳
  • 가장 불공평한 곳 — 특정 데이터에만 요청이 몰리는 곳 (인기 게시물,

유명 사용자)

세 번째가 실무에서 가장 자주 사람을 잡습니다. 평균으로 계산하면 여유가 넘치는데, 실제로는 1%의 데이터에 90%의 요청이 몰려서 무너집니다.

6단계 — 트레이드오프

마지막이자, 좋은 설계자와 부품 나열자를 가르는 단계입니다.

모든 선택에는 대가가 있습니다. 그것을 말하지 않으면 선택한 게 아니라 그냥 주워온 것입니다.

  • 캐시를 뒀다 → 오래된 값이 잠깐 보일 수 있다. 얼마나 잠깐? 그게 괜찮은

데이터인가?

  • 큐로 뒤로 뺐다 → 결과가 즉시 반영되지 않는다. 사용자에게 뭐라고 보여줄

것인가?

  • 복제본을 뒀다 → 방금 쓴 걸 못 읽을 수 있다.

이 단계에서 해야 할 말은 이런 모양입니다.

"캐시를 60초 두겠습니다. 그러면 링크가 삭제된 뒤에도 최대 60초는 열립니다. 이 서비스에서는 그 정도는 허용된다고 봅니다. 만약 삭제가 즉시 반영돼야 한다면, 삭제 시 캐시를 지우는 경로를 추가하고 그만큼 복잡도를 받겠습니다."

이렇게 말할 수 있으면 설계자입니다. "캐시를 두면 빨라집니다"만 말하면 부품 나열자입니다.

---

처음부터 끝까지 — URL 단축 서비스

6단계를 실제로 돌려 봅시다.

1. 요구사항 명확화

  • 기능: 긴 주소를 짧은 주소로 만든다. 짧은 주소를 누르면 원래 주소로 보낸다.
  • 품질: 이동은 200밀리초 안에. 거의 안 죽어야 한다. 짧은 주소는 절대 다른

곳으로 가면 안 된다.

  • 범위 밖: 클릭 통계, 사용자 계정, 커스텀 주소. 이번엔 안 합니다.

2. 규모 추정

  • 하루 새 링크 100만 개 → 초당 약 12건 (쓰기)
  • 링크 하나당 평균 100번 눌림 → 하루 1억 번 → 초당 약 1,200건 (읽기)
  • 읽기:쓰기 = 100:1

이 비율 하나가 모든 것을 말해줍니다. 이건 읽기 시스템입니다. 쓰기 최적화에 시간을 쓰면 안 됩니다.

  • 5년 보관 → 링크 18억 개 → 하나에 500바이트면 약 1TB. 한 대에 들어갑니다.

샤딩은 필요 없습니다. (숫자를 안 셌으면 괜히 샤딩을 넣었을 것입니다.)

3. API와 데이터 모델

POST /urls   {longUrl} → {shortCode}
GET  /{shortCode}       → 301/302 리다이렉트
urls: shortCode(키) → longUrl, createdAt

키 하나로 값 하나를 꺼내는 것뿐입니다. 조인도, 검색도, 범위 질의도 없습니다. 이렇게 단순한 접근 패턴은 캐시가 완벽하게 먹힙니다.

4. 상위 설계

가장 단순하게 시작합니다: 사용자 → 서버 → DB. 이제 숫자를 댑니다.

  • 읽기 초당 1,200건, 서버 하나가 40건 → 로드밸런서 + 서버 여러 대
  • DB는 초당 30건 → 1,200건을 절대 못 받습니다. 캐시가 필수입니다.
사용자 → 로드밸런서 → 서버 여러 대 → 캐시 → 데이터베이스

선 하나하나에 숫자가 붙어 있습니다.

5. 병목 심화 — 인기 링크

DB가 초당 30건인데 읽기는 1,200건입니다. 캐시가 이걸 흡수해야 합니다. 흡수할 수 있을까요?

여기서 불공평함이 등장합니다. 링크가 18억 개지만 요청은 극소수의 인기 링크에 몰립니다. 방금 SNS에 올라간 링크 몇 개가 오늘 클릭의 대부분을 차지합니다.

이건 나쁜 소식처럼 들리지만 사실 최고의 소식입니다. 인기 링크 몇천 개만 캐시에 있으면 요청의 95% 이상이 캐시에서 끝납니다. 캐시에 18억 개를 다 넣을 필요가 없습니다.

  • 캐시 적중률 95% → DB로 가는 건 초당 60건
  • 아직 30건보다 많군요 → 적중률을 98%로 올리거나, 읽기 복제본을 하나 둡니다

이게 병목 심화입니다. 숫자를 대고, 안 맞으면 부품을 더하고, 다시 셉니다.

6. 트레이드오프

  • 캐시 유효시간 60초 → 링크를 지워도 최대 60초는 열립니다. 스팸 링크를

즉시 차단해야 한다면 삭제 시 캐시를 지우는 경로가 필요합니다. 이번 범위에서는 60초를 받아들입니다.

  • 짧은 코드 생성 → 무작위로 만들면 충돌을 확인해야 하고, 순번으로 만들면

다음 코드를 남이 추측할 수 있습니다. 이 서비스는 비밀 링크가 아니므로 순번 방식의 단순함을 택하겠습니다.

  • 샤딩 안 함 → 1TB는 한 대에 들어갑니다. 나중에 10배가 되면 그때

shortCode 기준으로 나눌 수 있습니다. 지금 넣지 않는 것이 옳습니다.

---

마지막 조언

이 6단계에서 사람들이 가장 많이 건너뛰는 것은 2단계(규모 추정)입니다. 그리고 그것이 나머지를 전부 망칩니다. 숫자가 없으면 4단계의 부품들이 "있으면 좋을 것 같아서" 놓인 장식이 되고, 5단계에서 무엇이 병목인지 말할 수 없고, 6단계에서 무엇을 포기했는지도 말할 수 없습니다.

그리고 기억할 것 하나.

설계에 정답은 없습니다. 근거 없는 선택이 오답일 뿐입니다.

다음 두 강의에서 이 6단계를 직접 적용해 볼 것입니다. 먼저 URL 단축 서비스, 그다음 뉴스 피드입니다.

이 강의가 단순화한 것

교육용 모형은 언제나 무언가를 생략합니다. 무엇을 생략했는지 아는 것도 학습의 일부입니다.

전제한 것

  • 이 6단계는 널리 쓰이는 관행을 정리한 것이지 표준 규격이 아니다. 조직과 문제에 따라 순서와 비중이 달라진다.
  • 본문의 URL 단축 서비스 숫자는 설명을 위해 고른 예시이며 특정 서비스의 실제 지표가 아니다.
  • 캔버스의 그림은 4단계의 결과물 예시일 뿐이며, 이 구조가 모든 문제의 정답은 아니다.
  • 규모 추정은 자릿수만 맞추는 것을 목표로 한다. 정밀한 용량 산정은 별도의 작업이다.

다루지 않은 것

  • 비용 산정과 예산 제약
  • 팀 구조와 조직이 아키텍처에 미치는 영향(콘웨이의 법칙)
  • 보안, 규제 준수, 데이터 주권 요구사항
  • 기존 시스템에서 점진적으로 옮겨가는 마이그레이션 전략

더 읽을거리: System Design Interview — 6-step framework · Google SRE Book — Handling Overload

이 강의에 물어보기

하루 5번

이 강의 본문만 근거로 답합니다. 강의에 없는 내용은 지어내지 않습니다.