나 JAVA 봐라

[가상 면접 사례로 배우는 대규모 시스템 설계 기초] 1장 사용자 수에 따른 규모 확장성 본문

DevOps, MLOps/독서

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

cool_code 2024. 5. 31. 00:45

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

하나의 서버 내에 웹 앱, DB, 캐시 등이 다 있을 수 있지만, 사용자 수가 많아짐(요구 사항)에 따라 각각의 서버(웹, DB, 캐시,... 등)로 분리할 수 있다.

 

웹 계층

    • 스케일 업(수직적 규모 확장) vs 스케일 아웃(수평적 규모 확장)
    • 스케일 업의 한계
      • 한 대의 서버에 CPU, 메모리를 무한대로 증설하는 데에 한계가 있다. (스케일 업 : 서버에 고사양의 CPU, RAM을 추가하는 행위)
      • 장애에 대한 자동복구(failover), 다중화 방안 없기에 장애 발생 시 서비스가 중단된다. (-> 즉, 한 대의 서버이기에 발생하는 문제)
      • -> 이런 단점으로 인해, 대규모 애플리케이션 지원하는데에는 스케일 아웃 많이 씀.
    • 로드 밸런서
      • 사용자 많을 때 부하 분산함.
      • 사용자는 로드밸런서의 공개 IP 주소로 접속(웹서버-클라이언트가 직접 연결 x) -> 로드밸런서가 사설 IP주소로 웹 서버 접속
      • 서버 간 통신에서는 사설 IP 주소 사용(보안적으로 좋음-> 같은 네트워크에 속한 서버 사이의 통신에만 사용 가능하기 때문) 
      • 서버가 2대 이상일 때, 한 대가 다운된다면 다른 서버가 처리할 수 있기에 서비스 전체가 다운되지 않는다.
      • 만약 감당할 없는 트래픽이 없으면, 간단하게 서버를 추가하면 로드밸런서가 자동적으로 트래픽을 분산한다.
      • -> 즉 보안/가용성/확장성 측면에서 유리하다!
  •  

데이터베이스 계층

  • DB 다중화 (replication) : 쓰기(create, delete,…) , 읽기(get) 연산에 따라 master-slave로 나눌 수 있음.
    • 쓰기 연산 : master DB에서만 지원. 
    • 읽기 연산 : slave DB에서 지원, 대부분의 애플리케이션은 읽기 연산이 훨씬 많기 때문에 slave DB가 더 많다.
    • (생각해볼 때, master DB가 더 많으면 쓰기 연산 여러군데에서 일어나는거 서로 동기화 계속 해야하기에 그에 대한 부담도 클듯,,, 뭐 물론 slave DB도 동기화해야하지만 master -> slave 동기화는 단방향이고 master <-> master는 양방향이니까? ) 
  • DB 다중화 하는 이유? 
    • 성능 : 요청 (쓰기, 읽기)에 따라 알맞은 DB가 처리하기에 병렬로 처리할 수 있는 질의(query) 수가 늘어남.
    • 안정성 : DB 일부가 파괴되어도 replication했기에 데이터를 보존할 수 있음.
    • 가용성 : DB 일부에 장애가 생겨도 다른 DB를 사용하기에 계속 서비스를 사용할 수 있음.
  • DB 서버 하나가 다운되면 발생하는 일
    • 부 서버 한 대뿐인데 다운된 경우 : 읽기 연산은 한시적으로 주 DB로 전달. 또한 새로 생성되는 부DB가 장애 서버를 대체한다.
    • 부 서버 여러 대인 경우: 읽기 연산은 나머지 부DB에서 처리. 또한 새로 생성되는 부DB가 장애 서버 대체
    • 주 DB 서버 다운: 한 대의 부DB가 새로운 주 서버되며, 모든 연산은 새로운 주 서버에서 처리한다. 또한 새로운 부 DB가 추가된다. 
      • => 만약 주서버 다운이 프로덕션 환경에서 발생했고, 부 서버의 데이터가 최신 상태가 아니라면 상황이 복잡해진다. 이러한 경우 복구 스크립트를 통해 없는 데이터를 추가하고, 다중 마스터/원형 다중화 방식을 도입하여 이런 상황에 대처해야한다. 
        • 다중 마스터 : 독립적으로 작동하는 마스터 여러 개 둠. 변경 사항을 다른 마스터로 전파하여 데이터 일관성 유지
        • 원형 다중화 : 노드가 원형으로 구성됨. 변경 사항을 다음 노드로 전파.

캐시 계층

    • 응답 시간 (latency) 줄이기 위해 사용하며, 정적 콘텐츠를 CDN으로 옮겨 개선할 수 있음. 
    • 애플리케이션 성능은 DB를 얼마나 자주 호출하냐에 따라 크게 좌우되기에, 캐시를 통해 성능을 개선할 수 있다. (캐시 통해 DB를 덜 호출한다.)
    • 보통 캐시도 데이터를 API 형식으로 주고받기에 사용이 편리하다. 
    • 캐시 유의할 점
      • 데이터의 변경이 자주 일어나면, 캐시 데이터와의 일관성이 없기에 변경이 많이 없는 데이터를 캐싱한다. 
      • 캐시 데이터의 만료 시점을 정해야한다. -> 만료 시점이 길면 원본과 차이가 클 수 있고, 짧으면 DB를 너무 자주 접근할 수 있다
      • 캐시 메모리가 너무 작으면 데이터가 너무 자주 캐시에서 밀려나버려 캐시 서버의 의미가 없을 수 있기에, 캐시 메모리를 과할당하여 방지할 수 있다. 
      • 캐시 메모리가 상태에서 데이터를 추가로 넣으려면 데이터를 방출해야하는데 LRU, FIFO,… 등의 데이터 방출 정책을 적용할 있다. 
      • 단일 캐시 서버의 경우 SPOF 발생할 수 있기에 캐시 서버도 분산해야한다. 
      • 캐시는 휘발성 데이터이기에, 중요한 데이터는 지속적 저장소에 두어야한다. 
    • CDN : 정적 콘텐츠를 전송하는 쓰이며, 지리적으로 분산된 서버의 네트워크

 

    • ++ ) 캐시 서버 예시
      • 인메모리 캐시 서버 : 세션 관리, 실시간 데이터 처리 등에 사용
        • Redis, Memcashed
      • 웹 캐시, 리버스 프록시 서버 : 웹 콘텐츠 캐싱
        • NGINX : 리버스 프록시, 로드 밸런서로 사용 & 정적 콘텐츠 캐싱
      • CDN 및 클라우드 기반
        • AWS CloudFlont : Amazon의 CDN 서비스. 정적/ 동적 콘텐츠 캐싱

무상태 웹 계층

  • 웹 계층을 ‘수평적’으로 확장하기 위해 상태 정보 (샤용자 세션)를 웹 계층에서 제거해야한다. 
    • 만약 삭제하지 않고 상태 정보를 보관하면, a의 인증 정보가 서버 1에 있을 때, a를 인증하기 위해 서버 1로만 계속 연결되어야 한다. -> 즉 같은 클라이언트는 같은 서버로만 라우팅 되어야 한다.
      • 로드 밸런서에서 스티키 세션(=고정 세션) 기능을 제공하지만, 1)로드 밸런서에 부담을 주고 2)새로운 서버를 제거, 생성하는 것도 복잡해진다. (=스케일 아웃 어렵다)
  • 만약 웹 서버에서 세션 정보를 저장해야한다면, 공유 저장소를 두는 것이 대규모 시스템에 더 적합하다. 
    • ++ 세션 공유저장소 : Redis, Memcashed 등의 인메모리 저장소가 '실시간' 응답에 유리하여 많이 씀. 만약 장기간 보관해야하면 휘발성있는 인메모리 보다 관계형DB 쓸 수도 있다. 

데이터 센터

  • 가용성 높이기 위해 여러 데이터 센터를 두는 것이 필요하다. 
  • 장애 없는 상황에서는 지리적 라우팅을 통해 제일 가까운 데이터 센터로 접속한다. 반면, 장애가 발생했을 경우, 장애 없는 데이터 센터로 전송된다.
  • 다중 데이터센터 아키텍처의 기술적 난제
    • 트래픽 우회 : 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 채택해야 함.(ex. geoDNS는 사용자 위치에 따라 IP주소 다르게 변환함)
    • 데이터 동기화 : 데이터 센터마다 별도의 DB 두는 경우, 장애가 자동 복구 되어서 다시 다른 데이터 센터로 접속한다면 해당 데이터 센터에는 찾는 데이터가 없을 수 있다. -> 데이터를 여러 데이터센터에 걸쳐 다중화하는 것이 필요함 (넷플릭스 다중화 전략 참고)
    • 테스트와 배포 : 웹 사이트, 애플리케이션이 여러 위치(데이터 센터)에서 잘 작동하는지 테스트하는 것이 필요하다. 자동화된 배포 도구가 있다면 동일한 서비스 설치되도록 하는데 중요한 역할을 한다. 

메시지 큐

  • 메시지 큐 : 데이터 무손실 보장하고, 비동기 통신을 지원하는 컴포넌트
  • Producer(생산자, 발행자) -> subscriber(소비자, 구독자)
  • 서버 결합 느슨해지기에, 규모 확장성 보장되어야 하는 안정적 애플리케이션을 구성하는 데에 좋다. 
    • 생산자: 소비자 서버가 다운되어 있어도 메시지 발행 가능
    • 소비자: 생산자 서버가 다운되어 있어도 메시지 수신 가능
  • 사용 예시) 이미지 크롭, 샤프닝, 블러링 지원하는 사진 보정 앱
    • 생산자 : 사진 보정 작업을 큐에 넣음
    • 소비자 : 해당하는 작업 프로세스가 해당 작업을 큐에서 꺼내서 비동기적으로 완료하기

로그, 메트릭, 자동화

  • 로그 : 에러 로그 모니터링하여 시스템 오류 찾아낸다. 서버 단위로 모니터링할 수도 있지만, 여러 서버의 로그를 단일 서비스로 모아주는 도구를 활용할 수도 있다. 
    • ex) ELK, Amazon CloudWatch Logs
  • 메트릭 : 메트릭을 수집하여 사업 현황에 관한 유용한 정보를 얻거나, 시스템의 상태를 파악할 수 있다. 
    • Ex) CPU, 메모리, 디스크I/O, MAU, DAU, 재방문, DB 계층 성능, 캐시 계층 성능 등
  • 자동화: 생산성 높이기 위해 자동화 도구 활용
    • Ex) CI 도와주는 도구 활용하여 개발자 코드를 자동으로 검증할 수 있도록 한다. (+ 빌드. 테스트, 배포 자동화 가능)

DB 규모 확장

      1. 수직적 확장 
        • CPU, RAM 등의 하드웨어를 무한 증설할 수 없다
        • SPOF로 인한 위험성이 크다
        • 고성능 서버로 수록 비용이 크다
      2. 수평적 확장 (= sharding)
        • 샤딩: 대규모 DB를 샤드라는 작은 단위로 중복 없이 분할하는 기술
        • 데이터를 어느 샤드에 둘지는 샤딩 키(=파티션 키)로 결정함. 샤딩 키는 데이터가 골고루 분포되도록 정해야 한다.
        • 샤딩 도입 시 고려할 문제
          • 데이터의 재 샤딩
            • 1) 데이터가 너무 많아져서 하나의 샤드로는 감당하기 어렵거나, 2)샤드 간 데이터 분포가 균등하지 못하여 샤드 소진 현상이 날 경우에 필요하다.
            • 샤드 키를 계산하는 함수를 변경하여 데이터를 재배치해야하는데, 안정 해시 기법을 활용할 수 있다.
          • 유명인사 문제 (= 핫스팟 키 문제)
            • 특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 문제. 
            • Ex) 차은우, 손흥민,…~ 같은 유명인사가 전부 같은 샤드에 저장되어 많은 read 연산으로 인한 과부하 발생
          • 조인과 비정규화
            • 하나의 DB 여러 샤드 서버로 쪼개고 나면, 여러 샤드에 걸친 데이터를 조인하기가 힘들어진다. -> 해결 위해 DB 비정규화하여 하나의 테이블에서 질의가 수행되도록 한다

정리

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