책 리뷰/가상 면접 사례로 배우는 대규모 시스템 설계 기초

가상 면접 사례로 배우는 대규모 시스템 설계 기초 - 1장

eess 2024. 8. 14. 02:16

 

🔖 1장 : 사용자 수에 따른 규모 확장성

읽은 날짜 : 2024.08.13

지은이 : 알렉스 쉬

출판사 : 인사이트

 

기억하고 싶은 내용

✔️ 시스템 규모 확장 방법 정리

  • 웹 계층은 무상태 계층으로
  • 모든 계층에 다중화 도입
  • 가능한 한 많은 데이터를 캐시할 것
  • 여러 데이터 센터를 지원할 것
  • 정적 콘텐츠는 CDN을 통해 서비스할 것
  • 데이터 계층은 샤딩을 통해 그 규모를 확장할 것
  • 각 계층은 독립적 서비스로 분할할 것
  • 시스템을 지속적으로 모니터링하고, 자동화 도구들을 활용할 것

 

단일 서버 아키텍처

  1. 사용자 단말(웹/앱)에서 도메인으로 접속
  2. DNS에 도메인을 조회하여 IP 주소로 변환
  3. IP 주소로 HTTP 요청
  4. HTML이나 JSON 응답

데이터베이스

  • 웹/모바일의 트래픽을 처리하는 서버와 데이터베이스 서버를 독립적으로 확장해 나갑니다.
  • 데이터베이스는 관계형 / 비관계형 중 선택해야 합니다.
    • 관계형 데이터베이스
      • 테이블, 열, 컬럼으로 데이터를 표현하고, 테이블 조인 가능
      • MySQL, Oracle, PostgreSQL 등
    • 비관계형 데이터베이스(NoSQL)
      • 테이블 조인 기능이 없다.
      • CouchDB, Neo4j, Cassandra, Amazon DynamoDB 등
      • NoSQL은 다시 네 분류로 나눌 수 있습니다.
        • 키-값 저장소
        • 그래프 저장소
        • 칼럼 저장소
        • 문서 저장소
    • 대부분 관계형 데이터베이스가 적합하나, 다음의 경우 NoSQL을 고려해볼 수 있습니다.
      • 아주 낮은 응답 지연시간이 요구될 때
      • 다루는 데이터가 비정형이라 관계형 데이터가 아닐 때
      • 데이터를 직렬화/역직렬화 할 수 있기만 하면 될 때
      • 아주 많은 양의 데이터를 저장할 필요가 있을 때

웹 계층의 수직적 규모 확장 vs 수평적 규모 확장

수직적 규모 확장(scale up)

  • 서버에 고사양 자원(더 좋은 CPU, 더 많은 RAM 등)을 추가하는 것
  • 트래픽 양이 적을 때 적합합니다.
  • 장점 : 단순합니다.
  • 단점 : 
    • 단일 서버에 자원을 증설하는 데에는 한계가 있습니다.
    • 장애 발생시 서비스가 중단됩니다. 장애에 대한 자동복구 방안이나 다중화 방안이 필요합니다.

수평적 규모 확장(scale out)

  • 더 많은 서버를 추가하여 성능을 개선하는 것
  • 대규모 애플리케이션 지원에 좀 더 적합한 방식입니다.
  • 로드밸런서가 필요해집니다.

로드밸런서

  • 부하 분산 집합에 속한 웹 서버들에게 트래픽 부하를 고르게 분산하는 역할
  • 사용자 단말은 로드밸런서의 공개(public) IP로 접속하고, 로드밸런서는 보안을 위해 서버의 사설(private) IP로 통신합니다.
  • 서버1이 다운되면 모든 트래픽은 서버2로 전송됩니다. ➡️ 장애 자동복구 & 가용성 향상!

데이터베이스 다중화 : master-slave 구조

  • 원본은 주(master) 서버에, 사본은 부(slave) 서버에 저장하는 방식입니다.
  • 쓰기 연산(insert, delete, update)은 주 서버에서만 지원합니다.
  • 부 서버에서는 주 서버에서 그 사본을 전달받으며 읽기 연산(select)만 지원합니다.
  • 대부분 애플리케이션은 읽기 연산의 비중이 훨씬 높아서 부 서버의 개수가 더 많습니다.
  • 데이터베이스 다중화의 장점 :
    • 데이터베이스 서버가 분산되어 병렬로 처리하는 질의(query)가 늘어나 성능 향상을 기대할 수 있습니다.
    • 일부 데이터베이스 서버가 파괴돼도 다른 서버에 데이터가 보존됩니다.
    • 지역적으로 여러 장소에 복제하여 장애가 발생해도 다른 서버에서 가져와서 계속 서비스가 가능해집니다.
  • 추가적으로 생각해봐야 할 점
    • 부 서버가 다운된 경우
      1. 부 서버가 한 대라면 읽기 연산은 일시적으로 주 서버가 처리하고 즉시 새로운 slave 서버 추가
      2. 부 서버가 여러 대라면 다른 부 서버가 읽기 연산 처리
    • 주 서버가 다운된 경우
      1. 부 서버가 한 대라면 해당 서버가 새로운 주 서버가 되고 일시적으로 모든 연산 처리. 이후 새로운 slave 서버 추가.
      2. 부 서버에 보관된 데이터가 최신 상태가 아닐 수 있기 때문에, 없는 데이터는 복구 스크립트를 돌려서 추가.

캐싱

  • 캐시는 값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 요청이 보다 빨리 처리될 수 있도록 하는 저장소입니다.
  • 데이터베이스 부하를 줄이고 서버의 성능을 개선할 수 있습니다. 또한, 캐시 계층을 따로 두면 이를 독립적으로 확장시킬 수 있습니다.
  • 읽기 주도형 캐시 전략(read-through caching strategy)
    1. 웹서버가 캐시에 응답이 저장되어 있는지 보고 있으면 해당 데이터를 클라이언트에 반환합니다.
    2. 없으면 데이터베이스에서 찾아서 캐시에 저장한 뒤 클라이언트에 반환합니다.

  • 캐시 사용시 유의할 점
    • 데이터 갱신은 자주 일어나지 않지만 참조는 빈번하게 일어날 때 고려해볼 만 합니다.
    • 영속적으로 보관할 데이터는 캐시에 두면 안 됩니다.
    • 너무 짧지도 길지도 않은 만료 기한을 두어야 합니다.
    • 저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 일관성이 깨질 수 있습니다.
    • 여러 지역에 걸쳐 캐시 서버를 분산시켜 단일 장애 지점이 되는 것을 피해야 합니다.
    • 캐시 메모리가 너무 작으면 데이터가 너무 자주 캐시에서 밀려나버려 성능 저하가 발생할 수 있습니다. ➡️ 캐시 메모리 과할당
    • 캐시 메모리가 꽉 차서 데이터를 방출해야 할 때 전략을 고려해야 합니다.
      • LRU(Least Recently Used)
      • LFU(Least Frequently Used)
      • FIFO(First In First Out)

콘텐츠 전송 네트워크(CDN)

  • CDN은 정적 콘텐츠를 전송하는 데 쓰이는, 지리적으로 분산된 서버의 네트워크입니다. 이미지, 비디오, CSS, JavaScript 파일 등을 캐시할 수 있습니다.
  • CDN 동작 과정 
    1. 사용자가 정적 콘텐츠 접근하면 CDN 서비스 사용자가 제공한 URL로 요청합니다.(사용자와 가장 가까운 곳으로)
    2. 콘텐츠가 CDN 서버에 없으면 원본 서버에 요청합니다.
    3. 원본 서버가 CDN 서버에 파일을 반환합니다. 이때 응답 헤더에 *TTL 값이 들어있습니다. TTL에 명시된 시간이 끝날 때까지 캐시됩니다.
      * TTL: Time To Live. 해당 파일이 얼마나 오래 캐시될 수 있는지 설명하는 값
    4. CDN 서버는 파일을 캐시하고 사용자에게 반환합니다. 
  • CDN 사용시 고려해야 할 사항
    • CDN은 제3사업자에 의해 운영되므로 데이터 전송 양에 따라 비용이 발생합니다. 자주 사용되지 않는 콘텐츠는 빼는 것을 고려해야 합니다.
    • 적절한 만료 시한 설정해야 합니다.
    • CDN 장애 발생 시 이를 감지하여 원본 서버로부터 가져오도록 클라이언트를 구성할 필요가 있습니다.
    • 캐시된 콘텐츠 무효화 : 캐시된 데이터와 원본 서버의 일관성을 유지하기 위해 아직 만료되지 않은 콘텐츠라도 CDN에서 제거할 수 있어야 합니다.
      1. CDN 서비스 사업자가 제공하는 API를 사용합니다.
      2. URL 마지막에 버전 번호를 주어 콘텐츠의 다른 버전으로 서비스할 수 있도록 합니다.

무상태 웹 계층

  • 상태 정보(세션 등)를 웹 계층에서 제거하고, RDBMS나 NoSQL, 캐시 시스템(Memcached, Redis)에 보관해야 합니다.
    • 웹 서버에서 상태 정보를 가지고 있으면 같은 사용자의 요청은 같은 서버로만 보내야 해서 자동 규모 확장이 어려워집니다.
    • 상태 정보를 공유 저장소에서 가져오도록 하여 웹서버로부터 물리적으로 분리해야 합니다.

데이터센터

  • 장애가 없는 상황에서 사용자는 가장 가까운 데이터센터로 안내됩니다. ➡️ 지리적 라우팅
  • 데이터센터 중 하나에 장애가 발생하면 모든 트래픽은 장애가 없는 데이터센터로 전송됩니다.
  • 기술적 난제
    • 트래픽 우회 : 사용자에게서 가장 가까운 데이터 센터로 트래픽을 보내줘야 합니다.
    • 데이터 동기화 : 데이터 센터마다 다른 데이터베이스를 사용하고 있는 경우 해당 데이터센터에 찾는 데이터가 없을 수도 있습니다. 이에 대한 보편적인 전략으로 데이터를 여러 데이터센터에 걸쳐 다중화하는 것입니다.
    • 테스트와 배포 : 자동화된 배포 도구를 사용하여 모든 데이터 센터에 동일한 서비스가 설치되도록 할 수 있습니다.

메시지 큐

  • 메시지의 무손실(메세지큐에 보관된 메시지는 소비가 꺼낼 때까지 안전히 보관됨)을 보장하는, 비동기 통신을 지원하는 컴포넌트
  • 동작 방식
    1. 생산자(또는 발행자)가 메시지를 만들어서 메시지 큐에 발행
    2. 소비자(또는 구독자)가 메시지를 받아 그에 맞는 동작 수행
  • 사용 예시
    • 사진 보정 애플리케이션 : 시간이 오래 걸릴 수 있는 사진 보정 프로세스를 메시지 큐에 넣고 비동기적으로 완료

로그, 메트릭 그리고 자동화

  • 서비스와 사업 규모가 커지면 로그, 메트릭, 자동화 같은 것들이 필요해집니다.
  • 로그 : 에러 로그 모니터링. 로그를 단일 서비스로 모아주는 도구 활용하면 편리합니다.
  • 메트릭 : 사업 현황에 관현 유용한 정보나 시스템 현재 상태를 파악할 수 있습니다.
    • 호스트 단위 메트릭 : CPU, 메모리, 디스크 I/O
    • 종합 메트릭 : 데이터베이스 계층의 성능, 캐시 계층의 성능
    • 핵심 비즈니스 메트릭 : DAU, 수익, 재방문
  • 자동화 : CI 도구로 빌드/테스트/배포 절차 자동화하여 개발 생산성을 향상시킬 수 있습니다.

데이터베이스 규모 확장

수직적 확장(scale up)

  • 기존 서버에 더 많은 고성능의 자원(CPU, RAM, 디스크 등) 증설
  • 한계
    • 서버 하드웨어의 한계로 무한 증설은 불가능합니다.
    • 단일 장애 지점으로 인한 위험성이 있습니다.
    • 자원 증설에 대한 비용이 증가합니다.

수평적 확장(sharding)

  • 더 많은 서버를 추가해서 성능 향상
  • 대규모 데이터베이스를 샤드(shard)로 분할하는 기술입니다.
  • 모든 샤드는 같은 스키마를 쓰지만, 샤드에 보관되는 데이터 사이에는 중복이 없습니다.
  • 샤딩 전략 구현시 가장 중요한 것은 샤딩 키를 어떻게 정하느냐입니다. 데이터를 고르게 분할할 수 있도록 하는 게 중요하기 때문입니다. 예를 들어, user 데이터를 user_id % 4를 해시 함수로 사용하여 데이터가 보관되는 샤드를 정합니다.

  • 샤딩 도입시 고려해야 할 점
    • 데이터의 재 샤딩 :
      • 데이터가 고르게 분포되지 못해 특정 샤드가 빠르게 소진될 수 있습니다.
      • 샤드 키 계산 함수 변경하고 데이터 재배치. 안정 해시 기법 활용.
    • 유명인사 문제 :
      • 특정 샤드에 질의가 집중되어 과부하가 걸리는 문제.
      • 예를 들어, SNS 애플리케이션을 구축할 때 유명인사가 전부 같은 샤드에 저장되면 과부하가 걸릴 수 있습니다.
    • 조인과 비정규화 :
      • 여러 샤드에 걸친 데이터를 조인하기가 힘들어지는 문제가 있습니다.
      • 데이터베이스 비정규화하여 하나의 테이블에서 질의 수행

 

오늘 읽은 소감

  • 처음 읽었을 때는 잘 이해가 가지 않았는데, 시간이 좀 흐르고 다시 읽어보니 대부분 이해가 되었다.
  • 항상 생각의 깊이가 코드 수준, 단일 서버 아키텍처 수준으로 머물러 있다는 느낌이 들었는데 1장의 내용을 통해 시스템 설계의 큰 그림을 대략 이해할 수 있었다. 각 기술의 세부적인 개념을 차차 채워나가야겠다.

 

궁금한 내용 & 잘 이해되지 않는 내용

데이터 직렬화 / 역직렬화

  • 데이터 직렬화(serialization)
    • 데이터를 파일이나 데이터베이스에 저장하거나, 네트워크를 통해 전송할 수 있는 형식으로 변환하는 과정입니다.
    • 직렬화의 결과는 일반적으로 바이너리 또는 JSON, XML 형식의 텍스트입니다.
    • 예시 : JavaScript의 JSON.stringfy()
  • 데이터 역직렬화(deserialization)
    • 직렬화된 데이터를 원래의 데이터 구조나 객체로 변환하는 과정입니다.
    • 예시 : JavaScript의 JSON.parse()

메시지 큐 사용 사례

언제 사용하면 좋을까?

  • 즉시 처리되기 어려운 요청에 대해 응답을 먼저 보내주고 작업을 나중에 처리하고 싶을 때
  • 어느정도 응답 지연이 허용되는 부가적인 기능
  • 시스템에서 특정 이벤트가 발생할 때 작업을 처리해야 하는 경우  
  • 여러 서버가 동시에 작업을 처리해야 하는 경우

사용 사례

  • 저장소에 대용량 파일 업로드 후 파일 변환이나 최적화 작업 
  • 푸시 알림이나 이메일 전송(비밀번호 재전송, 새로운 계정 생성 등)
  • 전자상거래 시스템에서 주문 처리, 재고 관리, 결제 처리 등의 작업을 비동기적으로 처리
  • 선착순 이벤트
  • 쿠폰 발급

구현 기술

  1. RabbitMQ
  2. Apache Kafka
  3. AWS SQS(Simple Queue Service)

참고

도서 - 가상 면접 사례로 배우는 대규모 시스템 설계 기초 1장 

메시지 큐 시스템의 이해와 활용

메시지 큐에 대해 알아보자!

우리 팀은 카프카를 어떻게 사용하고 있을까

message queue를 활용해보자