Zayson
A to Zayson!
Zayson
전체 방문자
오늘
어제
  • 분류 전체보기 (132)
    • Computer Science (20)
      • Network (4)
      • DB (12)
      • OS (4)
    • Algorithm (32)
      • 완전탐색(Brute-Force) (3)
      • 그리디(Greedy) (6)
      • 투포인터(Two-Pointer) (1)
      • 그래프(Graph) (5)
      • BFS & DFS (9)
      • 구현, 시뮬레이션(Implementation) (5)
      • 다이나믹 프로그래밍(DP) (3)
    • Backend (51)
      • Spring Boot (19)
      • JPA (16)
      • Kafka (2)
      • Java (13)
      • Kotlin (1)
    • DevOps (1)
      • Jenkins (5)
      • Oracle Cloud Infrastructure (1)
      • Kubernetes & Docker (1)
    • Trouble Shooting (3)
      • JPA (1)
      • Spring Boot (2)
    • 회고 (5)
      • 엔빵 프로젝트 포스트 로드맵 (1)
      • 2022년 (4)
    • Kafka (7)
      • Kafka (5)
      • Kafka Connect (2)
    • 기술 서적 (6)
      • 데이터 중심 애플리케이션 설계 (3)
      • 개발자가 반드시 정복해야할 객체 지향과 디자인 패턴 (2)
      • 가상 면접 사례로 배우는 대규모 시스템 설계 기초 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • 완전탐색
  • 프로그래머스
  • 관계형 데이터베이스 실전 입문
  • Java
  • Computer science
  • Backend
  • BFS
  • 그리디
  • dfs
  • spring boot
  • Kafka Connect
  • CS
  • 엔빵프로젝트
  • 나 혼자 스프링부트!
  • SpringBoot
  • JPA
  • 백준
  • kafka
  • 구현
  • 라이브스터디

최근 글

티스토리

hELLO · Designed By 정상우.
Zayson

A to Zayson!

1장. 사용자 수에 따른 규모 확장성
기술 서적/가상 면접 사례로 배우는 대규모 시스템 설계 기초

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

2024. 6. 30. 18:54

개요


  • 단일 사용자에서 다수의 사용자를 커버할 수 있는 시스템 확장에 대해 알아본다.

단일 서버


  • 단일 서버 사용 시 사용자의 요청 흐름
    • 사용자는 도메인 주소를 이용해 웹사이트 접속
      • DNS(Domain Name Service)를 이용해 도메인 주소 → IP 주소 변환
    • DNS가 반환한 IP 주소로 HTTP 요청을 전달
    • 웹 서버는 HTML 페이지 혹은 JSON 결과를 응답

데이터베이스


  • 서버는 웹 계층(트래픽 처리를 위한 웹 서버)과 데이터 계층(데이터베이스)을 구분하는 것이 좋다.
    • 계층을 분리함으로써 각각을 독립적으로 확장할 수 있다.

데이터베이스의 선택

  • 데이터베이스는 크게 관계형 데이터베이스와 비-관계형 데이터베이스 사이에서 선택한다.
    • 관계형 데이터베이스(RDB): MySQL, PostgreSQL 등
    • 비-관계형 데이터베이스(NoSQL): CouchDB, DynamoDB 등
  • NoSQL의 4가지 분류
    1. 키-밸류 저장소 (Key-Value Store)
    2. 그래프 저장소 (Graph Store)
    3. 컬럼 저장소 (Column Store)
    4. 문서 저장소 (Document Store)
  • NoSQL 선택이 권장되는 상황
    • Low-Latency가 필요한 경우
    • 데이터가 비정형(unstructured)이라 관계형 데이터가 아닌 경우
    • 데이터(JSON, YAML 등)를 직렬화/역직렬화할 수만 있으면 되는 경우
    • 많은 양의 데이터를 저장할 필요가 있는 경우

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


  • 수직적 규모 확장(Vertical Scaling): 스케일-업(Scale Up)을 의미, 서버에 고사양 자원을 추가하는 것
  • 수평적 규모 확장(Horizontal Scaling): 스케일-아웃(Scale Out)을 의미, 더 많은 서버를 추가해 성능을 개선하는 것
  • 스케일 업의 한계로 인해 대규모 애플리케이션 지원에 있어서는 스케일 아웃이 더 적절하다.
    • 서버 리소스를 무한정 늘리는 것은 불가능
    • Fail Over 방안이나 다중화(redundancy) 방안을 제시하지 않음

로드밸런서

  • 로드밸런서: 부하 분산 집합에 속한 웹 서버들에게 트래픽 부하를 고르게 분산하는 역할을 하는 장치
  • 사용자는 로드밸런서의 Public IP 주소로 접속하고, 로드밸런서는 Private IP를 사용해 내부 서버와 통신
Private IP는 같은 네트워크에 속한 서버 사이 통신에서만 사용 가능하며, 공인망(인터넷)을 통해 접근 불가능
  • 로드밸런서를 사용함으로써 웹 서버를 추가하면 Fail Over 상황을 방지하고 웹 서버 가용성을 향상시킬 수 있다.

데이터베이스 다중화

  • 데이터베이스 시스템은 Master/Slave 형태로 다중화를 지원
    • Master에서만 데이터 쓰기 연산을 지원
    • Slave에서는 데이터 읽기 연산만 지원
  • Master에 쓰여진 데이터를 Slave에서 제공하기 위해 Master로부터 데이터 복제본을 전달받는다.
  • 데이터베이스 다중화에 따른 이점
    • DB 작업의 대부분은 읽기 연산이며, Slave에서 읽기 연산을 제공하기 때문에 쿼리 요청이 분산되어 성능이 향상된다.
    • 자연재해와 같이 데이터 서버 일부분이 파괴되어도 지리적으로 떨어진 장소에 데이터를 다중화 시킬 수 있어 안정성이 높아진다.
    • 서버 장애가 발생해도 데이터를 여러 지역에 복제했기 때문에 가용성이 높아진다.
  • 데이터베이스 서버 장애 발생 시 동작
    • Slave에 장애가 발생한 경우 Slave가 1대라면 Master에서 읽기 연산을 처리하며, Slave가 여러대인 경우 장애가 발생한 Slave를 다른 Slave가 대체
    • Master에 장애가 발생한 경우 다른 Active Slave가 Master로 승격되어 Master 역할을 수행
💡 장애 발생 시 Master/Slave간 데이터가 동기화가 되지 않은 상황이 생길 수 있다.
(e.g Master 쓰기 연산 완료 후 데이터 복제본 Slave 전달 전 Master 장애 발생하는 경우)
- 복구 스크립트를 구성해 누락된 데이터를 추가하는 방안을 고려
- 다중 마스터(multi-masters), 원형 다중화(circular replication) 방안 고려
💡 Mutli-Master / Circular ReplicationMulti-Master
다중 마스터(multi-masters): 여러 마스터가 동시에 쓰기 작업을 처리하고 서로 복제하는 방식
- 고가용성: 하나의 마스터 장애시 다른 마스터가 쓰기 연산 처리 가능
- 로드 밸런싱: 쓰기 요청을 여러 마스터로 분산시켜서 수행 가능
- 지리적 분산: 마스터를 지리적으로 분산시켜 지역별 접근 속도 향상 가능

원형 다중화(circular replication): 데이터베이스 노드들이 원형으로 연결된 형태를 가지며, 이웃한 노드와 데이터를 복제하는 방식
- 고가용성: 한 노드가 장애가 발생해도 나머지 노드들이 데이터 복제 가능
- 로드 밸런싱: 이웃한 노드 간에만 데이터 복제가 이뤄지기 때문에 복제 과정에서 부하 분산
- 확장성: 새로운 노드를 추가하기 쉬움

두 방식 모두 데이터 일관성을 보장하기 어렵고, 각 노드에서 동시에 데이터 수정이 발생하는 경우 충돌 발생 가능성이 있이 이를 해결하는 것이 주요 도전과제이다.

캐시


  • 캐시(Cache): 값비싼 연산 결과, 자주 참조되는 데이터를 메모리에 두고 요청을 빠르게 처리하기 위한 저장소

캐시 계층

  • 데이터가 잠시 보관되는 곳으로 데이터베이스보다 빠르다.
  • 캐시 전략은 다양하며 가장 일반적인 전략은 주도형 캐시 전략(read-through caching strategy)이다.
    • 캐시 히트 시 클라이언트에 바로 반환
    • 캐시 미스 시 원본 데이터베이스를 쿼리 후 캐시에 데이터를 저장하고 반환하는 전략
캐시할 데이터 종류, 크기, 액세스 패턴에 맞게 다른 캐시 전략을 사용할 수 있다.

캐시 사용 시 유의할 점

  • 캐시 사용이 필요한 상황: 데이터 갱신이 자주 일어나지 않고, 데이터 참조는 자주 발생하는 경우
  • 캐시에 적재할 데이터 종류: 캐시는 휘발성 메모리이기 때문에 영속적 데이터는 DB에 두는 것이 바람직하다.
  • 캐싱된 데이터의 만료 기한: 캐싱할 데이터는 TTL을 걸고, TTL을 적절하게 지정해야 한다.
    • TTL이 짧은 경우 DB 조회가 많아진다.
    • TTL이 긴 경우 원본 데이터와 캐싱된 데이터 간 일관성이 떨어진다.
  • 일관성(Consistency): 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 일관성이 깨질 수 있다.
  • 장애 대응: 캐시 서버가 한대인 경우 단일 장애 지점(Single Point of Failure, SPOF)이 될 수 있으므로, 여러 지역에 걸쳐 캐시 서버를 분산시켜야 한다.
💡 단일 장애 지점 (Single Point of Failure, SPOF)
시스템 구성 요소에서 동작하지 않으면 전체 시스템이 중단되는 요소를 의미한다.
캐시 서버 장애 발생 시 SPOF가 되는 이유는 전체 시스템의 성능 및 가용성에 영향을 미치기 때문이다.
또한, 캐시 서버가 복구되었을 때 캐시 데이터를 로드하는 과정에서 데이터 일관성 문제가 발생할 수 있기 때문이다.
  • 캐시 메모리 크기: 캐시 메모리 크기가 작은 경우 데이터가 자주 캐시에서 밀려나 캐시 성능이 떨어진다.
  • 데이터 방출 정책: 캐시가 가득찼을 때 기존 데이터를 내보내는 정책이 필요하다.
    • LRU(Least Recently Used): 마지막으로 사용된 시점이 가장 오래된 데이터 제거
    • LFU(Least Frequently Used): 사용된 빈도가 가장 낮은 데이터를 제거
    • FIFO(First In, First Out): 가장 먼저 캐시에 들어온 데이터 제거

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


  • CDN은 정적 콘텐츠를 전송하는데 쓰이는 분산된 서버의 네트워크
  • 요청한 사용자와 가장 가까운 CDN 서버로부터 정적 콘텐츠를 내려줘 콘텐츠 로딩에 필요한 지연을 줄인다.
  • CDN의 동작
    1. 사용자가 CDN URL(CDN 사업자가 제공)로 이미지 접근
    2. CDN 서버에 이미지가 없는 경우 원본 서버에서 파일을 가져옴
    3. 원본 서버가 파일을 반환할 때 오는 HTTP Response 헤더에는 콘텐츠의 TTL 값을 갖고 있다.
    4. CDN은 파일을 TTL 기간동안 캐싱하며, 이후 동일한 콘텐츠 요청이 들어오는 경우 CDN에서 직접 반환

CDN 사용 시 고려사항

  • CDN은 제3 사업자에 운영되기 때문에 요금이 발생한다.
  • Time-Sensitive 콘텐츠의 경우 TTL시점을 잘 지정해줘야 한다
  • CDN 자체에 장애가 발생했을 때 콘텐츠를 제공하기 위한 대응책을 고려해야 한다.
  • TTL이 만료되지 않은 콘텐츠를 CDN에서 제거할 수 있어야 한다.
    • API를 사용한 삭제, 콘텐츠 오브젝트의 버저닝

무상태(Stateless) 웹 계층


  • 웹 계층을 수평적으로 확장하기 위해서는 상태 정보를 제거해야 한다.
  • 상태 정보를 데이터 계층에 저장하고, 필요할 때 가져오는 방식으로 구축해야 한다.

상태 정보 의존적인 아키텍처

  • 상태 정보 의존적인 아키텍처의 경우 상태를 유지해야 하기 때문에 해당 상태 정보를 갖고 있는 웹 서버에서만 요청을 처리할 수 있다.
  • 로드밸런서는 Sticky Session을 통해 같은 클라이언트라면 항상 같은 서버로 요청을 라우팅할 수 있지만, 로드밸런서에 부담이 가기 때문에 바람직하지 않다.

무상태 아키텍처

  • 무상태 아키텍처의 경우 상태 정보가 필요한 경우 공유 저장소(Shared Storage)에서 데이터를 가져온다.
  • 상태 정보는 웹 계층(웹 서버)와 물리적으로 분리되어 있어 사용자의 요청이 어떤 웹 서버로와도 문제가 없다.
    • 즉, 수평적 확장이 용이하며, 안정적이다.
  • 공유 저장소는 RDB, NoSQL 어떤 것을 사용해도 문제 없으며, 일반적으로 트래픽, 규모 확장을 고려해 NoSQL을 사용한다.

데이터 센터


 

  • 지리적 라우팅(geoDNS-routing): 장애가 없는 상황에서 사용자는 가장 가까운 데이터 센터로 라우팅 된다.
geoDNS는 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정하는 것
  • 장애가 발생하면 모든 트래픽은 장애가 없는 데이터 센터로 전송된다.
  • 다중 데이터 센터를 구축 시 고려사항
    • 트래픽 우회: 올바른 데이터 센터로 트래픽을 보내는 방법을 찾아야 한다. (GeoDNS)
    • 데이터 동기화: 데이터를 여러 데이터 센터에 다중화해야 한다.
    • 테스트와 배포: 여러 위치에서 테스트 해 각 데이터 센터가 정상적으로 동작하는지 확인해야 하며, 자동화된 배포 도구를 통해 모든 데이터 센터에 동일한 서비스가 구성되어야 한다.

메세지 큐


  • 메세지 큐: 메세지의 무손실(durability)를 보장하는 비동기 통신을 지원하는 컴포넌트
Durability: 트랜잭션이 완료된 메세지(메세지 큐에 보관된 메세지)는 손실되지 않고 안전한 것을 의미
  • 메세지 큐는 메세지 버퍼 역할을 하고, 비동기적으로 전송한다.
  • 메세지 큐의 동작
    • Publisher/Producer 는 메세지 큐에 메세지를 전송한다.
    • Subscriber/Consumer는 메세지를 받아 로직을 처리한다.
  • 메세지 큐를 사용하면 서비스/서버 간 결합이 느슨해지기 때문에 확장성이 보장된 애플리케이션에서 사용하기 좋다.

로그, 메트릭, 자동화


  • 로그, 메트릭, 자동화를 통해 서비스의 생산성 및 품질을 향상시킬 수 있다.
  • 에러 로그 모니터링을 통해 오류와 문제를 빠르고 쉽게 파악할 수 있다.
    • 로그를 단일 서비스로 모아주는 도구를 활용하면 유용하다. (e.g ELK 등)
  • 메트릭 수집을 통해 시스템의 현재 상태를 쉽게 파악할 수 있다.
    • 유용한 시스템 메트릭
      • 호스트 단위 메트릭 (CPU, 메모리, 디스크 I/O)
      • 종합 메트릭 (데이터베이스 계층 성능, 캐시 계층 성능 등)
      • 핵심 비즈니스 메트릭 (DAU, 수익 등)
  • CI/CD를 이용해 코드의 통합 및 배포 자동화를 통해 생산성을 향상시킬 수 있다.

데이터베이스의 규모 확장


  • 데이터베이스의 규모를 확장하는 방법에는 수직적 확장과 수평적 확장이 있다.

수직적 확장

  • 기존 서버에 더 많고 좋은 리소스(CPU, RAM, 디스크 등)를 추가하는 방법
  • 수직적 확장의 한계
    • 리소스를 무한히 증설시킬 수 없기 때문에 한계가 명확하다.
    • SPOF로 인한 위험성이 크다.
    • 비용이 많이 든다.

수평적 확장 (샤딩)

  • 데이터베이스를 샤드(shard)라는 작은 단위로 분할해 확장시키는 방법
  • 모든 샤드는 같은 스키마를 쓰지만, 샤드 별 보관되는 데이터 사이엔 중복이 없다.
  • 샤딩 키(파티션 키)를 적절히 정해 각 샤드에 고르게 데이터가 분배되도록 구성하는 것이 중요하다
  • 샤딩 사용 시 발생하는 문제
    • 데이터의 재샤딩: 샤드 소진 현상이 발생할 때 샤드 키를 계산하는 방식을 변경해 데이터 재배치 필요
    • 유명인사 문제(핫스팟 키 문제): 특정 샤드에 쿼리가 집중되어 특정 서버에 과부하가 걸리는 문제
    • 조인과 비정규화: 샤딩을 사용하면 여러 샤드에 걸친 데이터를 조인하기 힘들다.
      • 데이터베이스 비정규화를 통해 하나의 테이블에서 쿼리 수행을 통해 해결할 수 있다.

정리


  • 시스템 설계 시 각 계층에 대해 다중화를 도입하자.
    • 데이터 계층은 샤을 통해 규모를 확장하자.
  • 각 계층은 독립적인 서비스로 분할하자.
  • 웹 계층은 무상태 계층으로 구성하자.
  • 가능한 많은 데이터를 캐시하고, 정적 콘텐츠는 CDN을 사용하자.
  • 시스템을 지속적으로 모니터링하고 자동화 도구를 활용하자.
반응형
저작자표시 비영리 변경금지 (새창열림)
    Zayson
    Zayson
    공부한 내용을 정리하는 공간

    티스토리툴바