CHAPTER1. 사용자 수에 따른 규모 확장성

  • 수백만 사용자를 지원하는 시스템을 설계하는 것은 지속적인 계량과 끝없는 개선이 요구되는 여정

단일 서버

  • 사용자 요청 처리 흐름
    1) 사용자는 도메인 이름을 이용하여 웹사이트에 접속
    2) DNS에 질의하여 IP주소로 변환(DNS 는 우리 시스템의 일부는 아니다.)
    3) IP 주소로 HTTP 요청이 전달
    4) 요청 받은 웹 서버(우리 시스템)은 HTTP 나 json 응답 파일 반환한다.

데이터베이스

사용자가 늘면 하나의 서버로는 충분하지 않아서 여러 서버를 두어야한다. 하나는 웹/모바일 트래픽 처리 용이고 다른 하나는 데이터베이스 용이다. 두 서버를 분리하면(웹 계층, 데이터 계층) 각각을 독립적으로 확장해갈 수 있게 된다.

어떤 데이터 베이스를 사용할 것인가?

  • 관계형(Relational Database Management System)
    • 전통적
    • 자료를 테이블의 열과 칼럼으로 표현
    • 테이블 조인 가능
  • 비관계형(NoSQL)
    • key-value store, column store, document store, graph store
    • 일반적으로 조인 연산 지원 안함
    • 다음과 같은 경우 유리하다.
      • 아주 낮은 응답 지연시간이 요구됨
      • 다루는 데이터가 비정형이라 관계형 데이터가 아님
      • 데이터를 직렬화 하거나 역직렬화 할 수 있기만 하면 됨
      • 아주 많은 양의 데이터를 저장할 필요가 있음

수직적 규모 확장 vs 수평적 규모 확장

수직적 규모 확장

  • 스케일 업, 서버에 고사양 자원을 추가
  • 트래픽의 양이 적을 때는 좋은 선택

수직적 규모 확장의 한계

  • 한 대의 서버에 CPU나 메모리를 무한대로 증설할 방법은 없다.
  • 장애에 대한 자동 복구 방안이나 다중화 방안을 제시하지 않는다.

수평적 규모 확장

  • 스케일 아웃, 더 많은 서버를 추가하여 성능 개선

로드 밸런서

  • 부하 분산 집합에 속한 웹 서버들에게 트래픽 부하를 고르게 분산하는 역할
  • client에서 public ip(로드밸런서)로 접근하면 private [[IP]]가 할당된 서버로 요청을 보낸다.
  • 장애를 자동 복구 하지 못하는 문제 해소, 웹 계층의 가용성 향상
  • 실제 동작)
    • 서버1이 다운되면 모든 트래픽 서버2로 전송
    • 웹사이트로 유입되는 스태픽이 가파르게 증가하면 웹서버 계층에 더 많은 서버를 추가

데이터베이스 다중화

  • 서버 사이에 master-slave 관계를 설정하고 원본은 master에 사본은 slave에 저장하는 방식
  • 쓰기 연산은 마스터에서만 지원한다. slave 데이터 베이스들은 사본을 전달받으며 읽기 연산만을 지원한다.
    • 대부분의 애플리케이션은 읽기 연산의 비중이 쓰기 연산보다 훨씬 높다.
  • 장점
    • 좋은 성능: 읽기 연산이 분산 처리 되므로, 병렬로 처리되는 쿼리수가 늘어나 성능 좋아짐
    • 안정성: 데이터베이스 서버 중 일부가 파괴되어도 데이터 보존됨.
    • 가용성: 장애가 발생하더라도 다른 서버에 있는 데이터를 가져와 계속 서비스할 수 있게 됨
  • 실제 동작)
    • 부서버 모두 다운되면, 읽기 연산은 모두 주데이터베이스에서 처리, 새로운 부서버 생성하여 장애서버 대신함.
    • 주서버가 다운되면 부 서버가 새로운 주 서버가 됨,
      • 부서버에 보관된 데이터가 최신 상태가 아닐 수 있음. 없는 데이터는 복구 스크립트를 돌려서 추가해야한다. #Q 왜 최신 상태가 아닐 수 있지? 그럼 읽기 연산도 부 서버에서 하면 부정확한거 아닌가?

캐시

  • 캐시는 비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고 뒤 이은 요청이 보다 빨리 처리될 수 있도록 하는 저장소
    • 애플리케이션 성능은 데이터베이스를 얼마나 자주 호출하느냐에 크게 좌우된다. 캐시는 그런 문제를 완화
  • 캐시 계층은 데이터가 잠시 보관되는 곳으로 데이터베이스보다 훨씬 빠르다. #Q 어떻게?
  • 요청을 받은 웹서버는 캐시 저장소에 응답이 저장되어있는지 확인하고 있으면 반환, 없으면 데이터베이스에 질의한다.
  • 캐시 사용시 유의점
    • 캐시는 어떤 상황에 쓰나: 데이터 갱신은 적고 참조는 잦을 때
    • 어떤 데이터를 캐시해야하나: 영속적으로 보관할 데이터는 좋지 않음. 캐시 서버 재시작하면 데이터 사라짐
    • 만료: 너무 짧으면 데이터베이스 참조 자주하고 너무 길면 원본과 차이남
    • 일관성: 저장소의 원본과 캐시내 사본이 같은지
    • 장애: 여러 지역에 걸쳐 캐시서버 분산
    • 캐시 메모리는 얼마나 크게 잡을 것인가?: 메모리 너무 작으면 성능 떨어짐. 과할당
    • 데이터 방출 정책: 캐시 꽉차면, 보통 LRU, LFU

CDN

  • 정적 콘텐츠 전송하는데 쓰이는, 지리적으로 분산된 서버의 네트워크. 이미지, 비디오, CSS, js 파일 등 캐시 가능

무상태 웹 계층

  • 웹계층을 수평적으로 확장하기 위해 상태 정보를 웹 계층에서 제거해야한다.
  • 서버가 상태정보를 가지고 있다면, 동일한 사용자의 요청은 동일한 서버에서만 처리되어야하기 때문에 한계를 지닌다.
    • 이를 위해 로드밸런서가 고정 세션(sticky session)이라는 기능을 제공하는데
      • 로드밸런서에 부담을 주고
      • 로드밸런서 뒷단에 서버를 추가하거나 제거하기도 까다로워진다.
  • 무상태 아키텍처로 상태정보를 따로 분리해서 저장하면, 관리가 편하다.

데이터 센터

  • geoDNS는 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정하는 DNS 서버
  • 데이터 센터 중 하나가 장애가 발생하면 ?
    • 다른 가까운 데이터 센터로 보내주는 로직이 있어야함
    • 데이터 동기화: 데이터를 여러 센터에 걸쳐 다중화 해 놓아야 함
    • 테스트와 배포: 여러 데이터 센터를 사용하도록 시스템이 구축된 상황이라면, 웹사이트 또는 애플리케이션을 여러 위치에서 테스트해봐야한다.

메시지 큐

  • 메시지의 무손실을 보장하는 비동기 통신을 지원하는 컴포넌트
  • 퍼블리셔가 메시지를 만들어 메시지 큐에 발행하면, 섭스크라이버가 메시지를 받아 동작을 수행하는 구조
  • 메시지 큐를 이용하면 서비스 또는 서버간 결합이 느슨해져서 규모 확장성이 모장되어야 하는 애플리케이션을 구성하기 좋다.

로그, 메트릭, 자동화

  • 로그: 에로 로그 모니터링. 장애 분석 쉬움.
  • 메트릭: 사업 현황에 유용한 정보를 얻을 수 있고, 시스템의 현재 상태를 쉽게 파악할 수 있음
    • 호스트 단위 메트릭: CPU, 메모리, 디스크I/O에 관한 메트릭
    • 종합 메트릭: 데이터베이스 성능, 캐시 성능
    • 핵심 비즈니스 메트릭: DAU, revenue, retention…
  • 자동화: 지속적 통합, 빌드 배포, 테스트

데이터베이스 규모 확장

수직적 확장 -> 아까 다룸
수평적 확장

  • 샤딩이라고도 부른다. 샤드라고 부르는 작은 단위로 분할한다.
  • 샤딩키를 어떻게 정하느냐가 중요
    • 데이터를 고르게 분할할 수 있도록해야한다.
  • 수평적 확장할 때 풀어야 할 문제
    • 데이터 재 샤딩: 데이터가 너무 많아져서 하나의 샤드로 감당 어렵거나, 데이터 분포에 문제가 있을 때, 샤드 키 계산하는 함수를 변경하고 데이터를 재배치 해야함
    • 유명인사 문제: 핫스팟키 문제, 특정 샤드에 질의가 집중되어 과부하가 걸리는 문제, 더 잘게 쪼갬
    • 조인과 비정규: 여러 샤드에 걸친 데이터를 조인하기 힘들어진다. 데이터 비정규화 하는 방법도 있음

CHAPTER2. 개략적인 규모 추정

  • 시스템 용량이나 성능 요구사항을 개략적으로 추정해볼 일이 있다.
  • 2의 제곱수, 응답지연 값, 가용성 관꼐된 수치들을 잘 이해해야한다.

2의 제곱수

응답지연 값

수치들에 기반한 결론

  • 메모리는 빠르지만 디스크는 아직도 느리다
  • 디스크 탐색은 가능한 피하라
  • 단순한 압축 알고리즘은 빠르다.
  • 데이터를 인터넷으로 전송하기 전에 가능하면 압축하라(패킷 왕복 지연시간은 엄청 크다.)
  • 데이터 센터는 보통 여러 지역에 분산되어 있고, 센터들 간에 데이터를 주고받는 데는 시간이 걸린다.

가용성에 관계된 수치들

CHAPTER3. 시스템 설계 면접 공략법

시스템 설계 면접은 두 명의 동료가 모호한 문제를 풀기 위해 협력하여 그 해결책을 찾아내는 과정에 대한 시뮬레이션이다. 정답은 없으며 아래와 같은 것들을 보는 자리이다.

  • 설계 기술
  • 설계 과정에서 내린 결정들에 대한 방어 능력
  • 면접관의 피드백을 건설적인 방식으로 처리할 자질

면접관은 면접자가 협력에 적절한 사람인지, 압박이 심한 상황도 잘 헤쳐 나갈 자질이 있는지, 모호한 문제를 건설적으로 해결한 능력이 있는지, 좋은 질문을 던질 능력이 있는지 또한 평가할 수 있다.

효과적 면접을 위한 4단계 접근법

1단계 - 문제 이해 및 설계 범위 확정

깊이 생각하고 질문하여 요구사항과 가정들을 분명히 하라. 중요한 것은 시스템 구축에 필요한 정보를 보아 올바른 가정을 하는 것이다.

  • 질문 예시
    • 구체적으로 어떤 기능을 만들어야 하나?
    • 제품 사용자 수는 얼마나 되나?
    • 회사의 규모는 얼마나 빨리 커지리라 예상하나? 석달, 여섯달, 일년 뒤의 규모는 얼마가 되리라 예상하나?
    • 회사가 주로 사용하는 기술 스택은 무엇인가? 설계를 단순화하기 위해 활용할 수 있는 기존 서비스로는 어떤 들이 있는가?

2단계 - 개략적인 설계안 제시 및 동의 구하기

  • 설계안에 대한 청사진을 제시하고 의견을 구하라. 면접관을 팀원처럼 대하라. 훌륭한 면접관들은 지원자들과 대화하고 설계과정에 개입할 것이다.
  • 핵심 컴포넌트를 포함하는 다이어그램을 그려라. ex) 클라이언트(웹/모바일), API, 웹 서버, 데이터 저장소, 캐시, CDN, 메시지 큐
  • 최초 설계안이 시스템 규모에 관한 제약사항을 만족하는지 개략적으로 계산해보아라(이러한 추정이 필요한지는 미리 물어봐라)
  • 가능하다면 시스템의 구체적 사용 사례도 몇 가지 살펴보자

3단계 - 상세 설계

대상 컴포넌트 사이의 우선순위를 정하는 단계일 것이다.

  • 시스템 성능, 시스템의 병목 구간이나 자원 요구량 추정치에 대한 질문을 할 수 있다.
  • 특정 시스템 컴포넌트의 세부사항을 깊이 있게 설명하는 것을 원할 수 있다.

4단계 - 마무리

아래와 같은 것을 하길 추천한다.

  • 추가적인 개선 가능 지점
  • 설계에 대한 요약
  • 오류가 발생하면 무슨 일이 생기는지
  • 운영 이슈(메트릭 수집 방법, 모니터링, 로그, 배포 등)
  • 규모 확장 요구

시간 배분(추천)

1단계 - 문제 이해 및 설계 범위 확정 3~10분
2단계 - 개략적 설계안 제시 및 동의 구하기 10~15분
3단계 - 상세 설계 10~25분
4단계 - 마무리 3~5분

CHAPTER4. 처리율 제한 장치의 설계

처리율 제한 장치 : 클라이언트 또는 서비스가 보내는 트래픽의 처리율을 제어하기 위한 장치

http의 경우 특정 기간 내에 전송되는 클라이언트의 요청 횟수 제한할 수 있다. API 요청 횟수가 제한 장치에 정의된 임계치를 넘어서면 추가로 도달한 모든 호출은 처리가 중단 된다. 아래와 같은 일을 할 수 있다.

  • 사용자는 초당 2회 이상 새 글을 올릴 수 없다.
  • 같은 IP 주소로는 하루에 10개 이상의 계정을 생성할 수 없다.
  • 같은 디바이스로는 주당 5회 이상 리워드를 요청할 수 없다.

장점

  • DoS 공격에 의한 자원고갈 방지
  • 비용 절감
  • 서버 과부하를 막음

References

https://product.kyobobook.co.kr/detail/S000001033116