책너두 (코딩 인터뷰 완전분석) 27일차 (~213p)

메모

9. 시스템 설계 및 규모 확장성

  • 규모 확장성(scalability)은 가장 쉬운 종류의 문제임.
    • 이런 류의 문제들은’마술’ 같은 것이 있지 않고, 단순히 여러분이 실제 세계에서 어떻게 행동할지를 보기 위해 설계된 문제들임.
  • 이런 문제를 풀 떄는 실제 일을 하듯이 하면 됨.
    • 질문을 하고, 면접관을 끌어들여라. 장단점을 토론하라.
  • 시스템 설계는 좋은 해법과 나쁜 해법은 있지만 완벽한 해법은 없음.

문제를 다루는 방법

  • 소통하라.
  • 처음에는 포괄적으로 접근하라.
  • 화이트보드를 사용하라.
  • 면접관이 우려하는 부분을 인정하라.
  • 가정을 할 때 주의하라.
    • 잘못된 가정은 문제를 완전히 다르게 바꿔 버릴 수 있기 때문
  • 여러분이 생각하는 가정을 명확히 언급하라.
  • 필요하다면 어립잡아 보라.
  • 뛰어들라.
  • 이런 문제들은 최고의 설계를 해내는 것보다 대개 그 과정을 중요하게 본다.

시스템 설계 : 단계별 접근법

  • ex) TinyURL 시스템 설계

1단계 : 문제의 범위를 한정하라

  • 정확히 무엇을 구현하는지 설계 전 문제의 범위를 한정하라.
  • 주요한 특징이나 사용되는 사례를 나열해 보자.
    • URL을 TinyURL로 축약
    • URL을 분석
    • TinyURL과 연결된 URL을 검색
    • 사용자 계정 및 링크 관리

2단계 : 합리적인 가정을 만들라

  • 가정을 세우는 것은 괜찮지만 합당해야 함.
    • ex) 하루에 100명의 사용자를 처리할 수만 있으면 된다, 메모리 제약이 없다 → 합당 X
    • 하루에 최대 백만 개의 URL을 생성하는 시스템 → 합당함.
  • 제품에 대한 감이 있어야 할 수도 있음.
  • 통계적으로 데이터가 10분 정도 오래된 건 괜찮음.
    • 하지만 URL을 추가한 뒤, 10분 뒤에 동작한다면, 그 제품은 아무도 사용하지 않을 것임.

3단계 : 중요한 부분을 먼저 그리라

  • 시스템의 주요한 부분을 다이어그램으로 그려라.
    • 시스템의 처음부터 마지막까지 어떻게 동작하는지 그 흐름을 봐라.
  • 현재 단계에선 규모 확장성 문제를 무시해도 된다.

4단계 : 핵심 문제점을 찾으라

  • 기본적인 설계를 마친 뒤에 발생할 수 있는 핵심 문제에 집중해야 함.
  • 어느 부분이 병목지점일지, 시스템이 풀어야 할 주된 문제는 무엇인지 알아야 함.

5단계 : 핵심 문제점을 해결할 수 있도록 다시 설계하라

  • 핵심 문제가 무엇인지 알아냈다면 그에 맞게 여러분의 설계를 수정해야 함.
    • 시스템 전체를 갈아 엎을 수도 있음.
    • 자잘한 부분만 수정할 수도 있음. (ex : 캐시를 사용)
  • 앞에서 그린 다이어그램을 바뀐 설계에 맞게 수정하라.

규모 확장을 위한 알고리즘 : 단계별 접근법

  • 시스템 전체가 아닌, 단순한 시스템의 한 부분, 혹은 알고리즘을 설계해보라는 요청을 받기도함.
    • 이때도 반드시 규모 확장성을 고려해야 함.

1단계 : 질문하라

  • 문제를 제대로 이해했는지 질문 시간이 필요함.
  • 언급하지 않은 세부사항을 질문을 통해 얻어내라.

2단계 : 현실적 제약을 무시하라

  • 메모리 제약이 없고, 컴퓨터 한 대에서 모든 데이터를 다 처리할 수 있다고 가정하고 문제를 풀어라.

3단계 : 현실로 돌아오라

  • 컴퓨터 한 대에 저장할 수 있는 데이터의 크기가 얼마고, 데이터를 여러 조각을 쪼갰을 때 어떤 문제가 발생할지 생각해 보라.

4단계 : 문제를 풀어라

  • 2단계에서 발견한 문제점들을 어떻게 해결할지 생각해 봐야 함.
    • 문제를 완전히 해결할 수도 있고, 그 수준을 완화시키는데 그칠 수도 있음.
    • 가끔, 접근 방식 자체를 싹 다 바뀌어야 할 지도 모름
  • 순환적 접근법(iterative approach)이 일반적으로 유용한 접근법임.
    • 어떤 문제를 해결하면 또 다른 문제가 발생하고, 그 문제를 다시 해결해 나가고 이를 반복하는 작업을 뜻함.

시스템 설계의 핵심 개념

  • 시스템 설계 문제에 특정 개념을 알고 있으면 문제를 더 쉽게 풀 수 있음.

수평적(horizontal) vs. 수직적(vertical) 규모 확장

  • 시스템은 두 가지 방법으로 규모를 확장시킬 수 있음.

  • 수직적 규모 확장(vertical scaling)

    • 특정 노드의 자원(resource)의 양을 늘리는 방법임.
    • ex) 서버에 메모리를 추가해서, 서버의 처리 능력을 향상시킬 수 있음.
  • 수평적 규모 확장(horizontal scaling)

    • 노드의 개수를 늘리는 방법을 말함.
    • 서버 한 대가 다뤄야 하는 부하(load)를 줄일 수 있음.
  • 수직적 규모 확장이 일반적으로 수평적 규모 확장보다 쉬움.

    • 하지만, 메모리, 디스크 같은 것만 추가할 수 있으므로 제한적임

서버 부하 분산 장치(load balancer)

  • 규모 확장성이 있는 웹사이트의 프론트엔드 부분은 서버 부하 분산 장치(load balancer)를 통해서 제공됨.
    • 서버에 걸리는 부하를 여러 대의 서버에 균일하게 분산시킬 수 있음.
    • 서버 한 대 때문에 전체 시스템이 죽거나 다운되는 상황을 방지할 수 있음.
    • 물론, 서버 여러 대가 근본적으로 똑같은 코드와 데이터를 사용하도록 하는 네트워크를 구현해놔야 함.

데이터베이스 역정규화(denormalization)와 NoSQL

  • SQL 관계형 데이터베이스의 조인 연산은 시스템이 커질수록 굉장히 느려짐.
    • 조인 연산은 가능하면 피해야 함.
  • 역정규화가 이런 것 들 중 하나임.
    • 데이터베이스에 여분의 정보를 추가해서 읽기 연산 속도를 향상시킨 것을 의미함.
  • 혹은 NoSQL 데이터베이스를 사용할 수도 있음.
    • NoSQL은 조인 연산 자체를 지원하지 않음.
    • 따라서 자료를 저장할 때 조금 다른 방식으로 구성해 놓는데, 이 방식이 규모 확장성에 좋도록 설계되어 있음.

데이터베이스 분할(샤딩)

  • 샤딩(sharding)은 데이터를 여러 컴퓨터에 나눠서 저장하는 동시에 어떤 데이터가 어떤 컴퓨터에 저장되어 있는지 알 수 있는 방식을 말함.
  • 흔히 사용되는 분할 방식에는 다음이 있음.
    • 수직적 분할(vertical partitioning)
      • 자료의 특성별로 분할하는 방식임.
      • ex) 소셜 네트워크를 만들 때, 개인정보와 관련된 부분, 메시지와 관련된 부분과 같이 특성에 따라 자료를 분할할 수 있음.
      • 단점
        • 특정 테이블의 크기가 일정 수준 이상으로 커지면 데이터베이스를 재분할해야 할 수도 있음.
    • 키 혹은 해시 기반 분할
      • mod(key, n) 의 값을 이용해서 N개의 서버에 분할 저장하면 됨.
      • 한 가지 문제는 서버의 개수가 사실상 고정되어 있어야 한다는 점임.
        • 서버를 새로 추가할 떄마다 데이터를 다시 재분배해야 하는데, 굉장히 비용이 큰 작업임.
    • 디렉터리 기반 분할
      • 데이터를 찾을 때 사용되는 조회 테이블(lookup table)을 유지하는 방법임
      • 상대적으로 서버를 추가하기 쉽지만, 두 가지 심각한 단점이 있음.
        1. 조회 테이블이 단일 장애 지점(single point of failure)이 될 수 있음.
        2. 지속적으로 테이블을 읽는 행위가 전체 성능에 영향을 미칠 수 있음.
  • 실제로 많은 시스템 설계 전문가들은 결국엔 다양한 분할 방식을 사용함.

캐싱(caching)

  • 인메모리(in-memory) 캐시를 사용하면 결과를 굉장히 빠르게 가져올 수 있음.
    • 인메모리 캐시는 키-값(key-value)을 쌍으로 갖는 간단한 구조임.
    • 일반적인 애플리케이션과 데이터 저장소(data store)사이에 자리잡고 있음.
  • 애플리케이션이 어떤 자료를 요청하면 캐시를 먼저 확인한다.
    • 캐시가 해당 키 값을 갖고 있지 않으면 그때 데이터 저장소를 살펴본다.
  • 캐시를 할 때는 쿼리와 그 결과를 캐시하는 경우가 많음.
    • 혹은, 특정 객체를 캐시에 저장할 수도 있음.
    • ex) 웹 페이지의 어떤 부분을 렌더링한 결과나 혹은 블로그에 올라온 최근 포스팅 리스트

비동기식 처리 & 큐

  • 이상적이라면 속도가 느린 연산은 비동기식(asynchronous)으로 처리해야 함.
    • 하염없이 해당 연산이 끝나기를 기다릴 수 없기 때문

네트워크 성능 척도

  • 네트워크 성능을 측정할 때 사용되는 몇 가지 중요한 척도(metric)는 다음과 같음.
    • 대역폭(bandwidth)
      • 단위 시간에 전송할 수 있는 데이터의 최대치를 말함.
      • 보통, 초당 몇 비트(bit)를 보낼 수 있는지로 계산함.
    • 처리량(throughput)
      • 대역폭은 단위 시간에 전송할 수 있는 데이터의 최대치를 말하는 반면, 처리량은 단위 시간에 실제로 전송된 데이터의 양을 의미함.
    • 지연 속도(latency)
      • 데이터를 전송하는 데 걸리는 시간을 말함.
      • 발송자(sender)가 데이터를 보낸 시점부터 수신자(receiver)가 데이터를 받는 시점까지 걸린 시간을 말함.

MapReduce

  • 구글과 관련이 있음.
    • 현재는 구글에 국한되지 않고 널리 사용되고 있음.
  • MapReduce 프로그램은 보통 굉장히 커다란 데이터를 처리하는 데 사용됨.
  • MapReduce 프로그램을 사용하려면 맵(Map) 단계와 리듀스(Reduce) 단계를 구현해야 함.
    • 나머지 부분은 시스템이 알아서 처리할 것임.
  • Map은 데이터를 입력으로 받은 뒤 <key, value> 쌓을 반환함.
  • Reduce는 키와 키와 관련된 값들을 입력으로 받은 뒤 나름의 처리 과정을 거친 뒤 새로운 키와 값을 반환함.
    • 경우에 따라 이 결과를 또 다른 Reduce 프로그램에 넘길 수도 있음.
  • MapReduce는 많은 과정을 병렬로 처리할 수 있게 도와 주기 때문에 굉장히 커다란 데이터에 대해서도 규모 확장이 쉬워짐.

시스템 설계 시 고려할 점

  • 다음의 문제점들도 함께 고려해야 함.
    • 실패(Failures)
      • 시스템의 어떤 부분이든 실패 가능성이 존재함.
      • 실패에 대한 대비책을 준비해야 함.
    • 가용성(availability) 및 신뢰성(reliability)
      • 가용성은 사용 가능한 시스템의 시간을 백분율로 나타낸 것을 말함.
      • 신뢰성은 특정 단위 시간에 시스템이 사용 가능한 확률을 나타낸 것을 말함.
    • 읽기 중심 vs 쓰기 중심
      • 읽는 연산이 많은지, 쓰는 연산이 많은지에 따라 설계 방식이 달라질 수 있음.
      • 쓰는 연산이 많다면 큐를 사용하는 방법을 생각해 보라.
      • 읽는 연산이 많다면 캐시를 사용하는 것이 좋을 수도 있음.
    • 보안
      • 보안 위협은 시스템에 엄청난 해를 가할 수 있음.
      • 해당 시스템이 직면할 수 있는 문제점을 생각해보고, 그를 해결하기 위해 어떻게 시스템을 설계할지 생각해 보라.

‘완벽한’ 시스템은 없다.

  • TinyURL, 구글 맵스, 다른 어떤 시스템도 완벽하게 동작하는 시스템 설계란 존재하지 않음.
  • 모든 시스템에는 장단점이 존재함.

댓글

Designed by JB FACTORY