본문 바로가기
개발/대규모 시스템 설계

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

by Mingvel 2023. 2. 12.

단일 서버

  • 단일 서버에 사용자의 요청이 전달되는 과정
    1. dns 서버에 mingvel.com 의 ip 주소를 요청
    2. dns 서버로부터 mingvel.com의 ip 주소를 응답
    3. 요청 받은 mingvel.com의 ip 주소로 HTTP 요청
    4. 요청 받은 웹 서버는 html 혹은 json 응답

데이터베이스 (DB)

  • 관계형 데이터베이스 (RDBMS)
    • Mysql, Oracle, PostgreSQL 등등
      • 모든 자료는 테이블, 컬럼, 로 표현된다
      • SQL을 이용하여 데이터를 관계에 따라 Join 할 수 있다
  • 비 관계형 데이터베이스 (NoSQL)
    • Cassandra, HBase, DynamoDB 등등
      • 키-값 저장소 (key-value store)
      • 그래프 저장소 (graph store)
      • 컬럼 저장소 (column store)
      • 문서 저장소 (document store)
    • 비 관계형 데이터베이스가 바람직한 경우
      • 아주 낮은 응답 지연시간이 요구됨 (low latency)
      • 관계형 데이터가 아닌 비정형 데이터를 다뤄야 할 경우 (unstructured)
      • 데이터를 직렬화 하거나(serialize), 역 직렬화(deserialize) 하기만 하면 되는 경우
      • 아주 많은 데이터를 처리해야 할 경우

수직적 확장

  • 수직적 확장 (scale up)
    • 서버에 고사양 자원추가하는 행위
    • 서버에 유입되는 트래픽 양이 적을 때 사용
    • 수직적 확장의 단정
      • 수직적 확장의 물리적인 한계가 존재한다 (무한대로 시스템 자원을 추가할 수 없음)
      • failover(자동 복구) 나 redundancy(다중화) 방안을 제시할 수 없다 - 즉, 서버에 장애가 발생하면 모든 웹 사이트 및 서비스는 중단된다

로드밸런서

  • 로드밸런서에 접근할 수 있는 public ip를 공개하고, 실제 내부에선 private ip를 사용하여 서버와 통신한다
  • 로드밸런서에서 관리하는 부하 분산 집합새로운 서버를 추가하면, 수평적 확장의 단점을 극복할 수 있다
    • 자동 복구가 가능해진다
    • 다중 서버 구성이 가능하다 - 즉, 웹 서버의 가용성이 향상된다
  • 서버1이 다운되면 로드밸런서는 모든 트래픽을 서버2로 포워딩한다
    • 웹 사이트 및 서비스 전체가 중지하는 현상을 방지할 수 있다

데이터베이스 다중화

  • 많은 데이터베이스 관리 시스템이 다중화를 지원한다
    • 주로 master - slave 형태를 지원한다
    • master원본을, slave사본을 저장하는 방식이 일반적이다
    • master에서 insert, update, delete와 같은 쓰기 연상을 지원하고, slave에서 select 와 같은 읽기 연산을 지원하도록 한다
      • 보통은 읽기 연산 비중이 훨씬 높아, 1대의 master + 다수의 slave로 구성하는 경우가 일반적이다
    • 장점
      • 자연재해 상황에서 한개의 DB가 파괴 되더라도, 데이터를 안정하게 보존할 수 있다 - 안정성
        • master-slave 모델을 사용하면 병렬로 수행할 수 있는 질의 수가 많아지므로 성능이 좋아진다 - 성능 향상
    • 장애 상황
      • slave db가 한대인 상황에서 slave db에 장애가 발생한다면?
        • 모든 읽기, 쓰기 트래픽이 master db로 몰릴 것이고, 즉시 새로운 slave db가 장애 db를 대체할 것이다
      • slave db가 여러대인 상황에서 한 대의 slave db에 장애가 발생한다면?
        • 읽기 연산은 나머지 slave db로 분산될 것이며, 새로운 slave db가 장애 db를 대체할 것이다
      • master db가 다운되면?
        • 하나의 slave db가 새로운 master로 선출될 것이며 모든 db 연산은 새로 선출 된 master db에서 수행될 것이다
        • slave db가 master db로 선출되었기에, 새로운 slave db가 추가될 것이다
        • 손실된 데이터에 대해서는 recovery script(복구 스크립트)를 통해 복구해야한다
        • multi-master (다중 마스터) 로 대처 가능
        • circular replication (원형 다중화) 로 대처 가능

캐시 (Cache)

  • 캐시는 값비싼 연산 결과 또는 자주 사용되는 데이터메모리에 두고, 뒤이은 요청이 더 빠르게 처리될 수 있도록 하는 저장소이다
  • application 성능은 데이터를 얼마나 자주 호출하느냐에 따라서 크게 좌우되는데, 캐시는 그런 문제를 완화할 수 있다
  • 캐시 계층
    • 캐시 계층은 데이터가 잠시 보관되는 곳으로 DB보다 훨씬 빠르다
    • 별도의 캐시 계층을 두면, 데이터베이스 IO를 줄일 수 있다
    • DB IO가 줄었으니, application 성능이 더 향상될 수 있다
    • 캐시 게층은 그 규모를 독립적으로 확장할 수 있다
  • 전략
    • 읽기 주도형 캐시 전략 (read-through caching strategy)
      1. WAS에서 캐시 계층에 데이터 조회를 요청한다
      2. 캐시 계층에 데이터가 있으면 해당 데이터를 사용한다
      3. 캐시 계층에 데이터가 없으면 DB로부터 데이터를 조회한다
      4. DB로부터 조회 한 데이터를 캐시 계층에 저장한다
      5. 캐시 계층에 저장된 데이터를 WAS로 반환한다
  • memcache api example
SECONDS = 1
cache.set('myKey', 'hi there', 3600 * SECONDS)
cache.get('myKey')
  • 캐시 사용시 유의할 점
    • 데이터 갱신은 자주 일어나지 않지만, 데이터 조회가 빈번한 경우 캐시 도입을 고려해볼 만 하다
    • 캐시 서버가 재시작 되면 모든 데이터가 사라지기 때문에, 영속적인 데이터를 보관하는 것은 바람직하지 않다
    • 캐시의 적당한 만료 정책을 수립해야 한다
      • 만료 정책이 없으면 캐시 데이터는 계속 캐시 서버에 머무를 것이다
      • 만료 기한이 길면 데이터의 신선도가 떨어질 것이고 (원본과 차이 날 가능성이 높아진다)
      • 만료 기한이 짧으면 DB 조회가 더욱 빈번해질 것이다
    • 일관성은 어떻게 유지되는가?
      • DB 갱신 연산과 캐시 갱신 연산이 하나의 트랜잭션에서 이루어지지 않으면 데이터 일관성이 깨질 수도 있다
      • 여러 지역에 걸쳐 캐시 서버DB확장해나가면 캐시와 DB 사이의 일관성 유지는 어려운 문제가 될 수 있다
    • 장애 상황은 어떻게 대처할 것인가?
      • 캐시 서버를 한대만 쓸 경우 SPOF (single point of failure, 단일 장애 지점) 이 되어버릴 가능성이 있다
        • SPOF : 특정 지점에서의 장애가 전체 시스템의 동작을 중단시켜버릴 수 있는 경우, 해당 지점을 SPOF(단일 장애 지점) 이라고 부른다
        • SPOF를 피하기 위해 캐시 서버를 분산시켜야 한다
    • 캐시 메모리는 얼마나 크게 잡을 것인가?
      • 캐시 메모리가 너무 적게 할당되면 캐시 데이터가 자주 밀려나게 된다 (eviction) -> 캐시 성능 저하로 이어진다
      • 위 상황을 막을 방법은 캐시 메모리를 과할당 (over provision) 하는 것이다
        • 캐시 메로리를 과할당 할 경우 캐시에 보관 될 데이터가 갑자기 늘어났을 경우를 대비할 수 있다
        • 과할당의 단점이라고 뽑는다면 역시 시스템 자원을 사용하는 것이기에 물리적인 한계가 있다
    • 데이터 방출 (eviction) 정책은 무엇인가?
      • 캐시 메모리가 꽉 차면, 기존에 캐싱 되어 있던 데이터를 방출해야 한다. 이러한 정책을 eviction(방출) 정책이라고 한다
      • 가장 널리 쓰이는 방출 정책은 LRU (Least Recently Used) 정책이다
        • 가장 오래전에 사용 된 캐시 데이터방출한다 (사용 시점이 가장 오래된 데이터를 방출한다)
      • LFU (Least Frequently Used) 정책도 있다
        • 사용 빈도가 가장 낮은 데이터방출한다
      • FIFO 정책
        • 가장 먼저 들어온 캐시를 가장 먼저 방출한다

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

  • 정적 컨텐츠 전송에 쓰이는 지리적으로 분산 된 서버의 네트워크이다
  • request path, query string, cookie, request header 등의 정보에 기반하여 HTML 페이지를 캐싱하는 것이다
  • CDN 으로부터 정적 컨텐츠를 제공 받는 과정
    • 사용자 A가 CDN 서버에 정적 컨텐츠를 요청한다 (CDN 서버에서 제공하는 url로 요청한다)
    • CDN 서버의 캐시에 해당 데이터가 없는 경우 원본 서버에 데이터를 요청하여 파일을 요청한다
    • 원본 서버는 파일과 응답 Header에 TTL 값을 포함한다. (TTL 값은 얼마나 오래 캐시될 수 있는지를 수치화한 값이다)
    • CDN 서버는 응답받은 파일을 캐싱하고, 사용자 A에게 해당 파일을 반환한다
    • 사용자 B가 동일한 파일을 CDN 서버에 요청한다
    • CDN 서버에 캐싱 되어 있는 파일을 반환한다
  • CDN 사용시 고려 사항
    • CDN 서버는 3rd-party에 의해 운영되기에 비용적인 측면을 고려해야한다
      • CDN 서버는 보통 CDN 서버로 들어오고 나가는 전송 양에 따라 요금을 과금하기에 자주 사용되지 않는 컨텐츠CDN에서 빼는 것을 고려한다
    • 적절한 만료 시한 설정
      • 시의성(time-sensitive)이 중요한 컨텐츠는 만료 시점을 잘 고려해야 한다
    • CDN 장애시 대처 방안 마련
      • CDN 서버 자체가 죽었을 경우에 웹사이트 및 어플리케이션이 어떻게 동작해야하는지 고려해야한다
      • CDN 서버가 먹통일 경우, 원본 서버로 즉시 호출하도록 클라이언트 사이드에서 기능 구현을 고려해야 할 수 있다
    • CDN 컨텐츠 무효화
      • CDN 서비스가 제공하는 api를 통해 컨텐츠를 강제 무효화 한다
      • Object Versioning을 이용한다

무상태 웹 계층 (Stateless Web)

  • 수평적으로 확장할 때 무상태 웹 계층을 고려할 수 있다
  • 무상태 웹 계층은 웹 계층에서 상태 정보(사용자 세션 데이터)와 같은 데이터를 제거해야 한다
  • 제거 된 상태 정보RDBMSNoSQL 같은 지속성 저장소보관한다
  • Stateful 한 Web은 각 Web에서 사용자들의 인증 정보를 가지고 있기에, 1번 서버에서 인증한 사용자는 2번 서버에 접근할 경우 인증 에러가 발생할 수 있다

데이터 센터

  • 데이터 센터를 다중화 하면 재해 상황 발생 시 하나의 데이터센터가 마비된다고 하더라도 로드밸런서가 트래픽을 다른 데이터센터로 포워딩 할 수 있다
  • 해결해야 하는 기술적 난제
    • 트래픽 우회
      • 사용자에게서 가장 가까운 데이터센터트래픽을 보낼 수 있어야한다
      • 즉, 데이터 센터로 트래픽을 보내는 가장 효과적인 방법을 찾아야한다
    • 데이터 동기화
      • 데이터 센터마다 별도의 DB를 운용한다면 장애로부터 회복한다고 하더라도 데이터가 동기화되지 않아 찾는 데이터가 없을 수 있다
      • 데이터를 여러 데이터센터에 걸쳐 다중화 하는 보완 전략을 수립할 수 있다
    • 테스트배포
      • 모든 데이터 센터동일한 서비스실행되도록 자동화 된 테스트와 배포가 필요하다

메세지 큐

  • 메세지 큐는 비손실을 지원하고, 비동기 통신을 지원하는 컴포넌트이다
    • 비손실 : 메세지 큐에 들어온 데이터는 소비자가 꺼내기 전까지는 안전하게 보관된다
    • producer/publisher 가 메세지를 만들어 Queue에 발행한다
    • consumer/subscriber 가 Queue를 구독하여, 해당 메세지를 소비 한다
  • 서비스 간 결합도를 느슨하게 만들 수 있다!
  • 규모 확장성보장되어야 하는 안정적인 어플리케이션 환경구성할 수 있다
  • 생산자와 소비자는 어느 하나가 동작 불가능한 상태가 되었어도, 다른 하나는 여부와 관계 없이 동작이 가능하다
  • 메세징 발행/소비비동기로 처리 되기에 독립적인 서비스 확장이 가능하다

로그, 메트릭, 자동화

  • 로그
    • 로그를 모니터링하는 것은 중요하다
    • 로그를 단일 서비스로 모아주는 도구를 활용하면 더 좋다
  • 매트릭
    • 메트릭을 잘 수집하면 서비스 운용에 유용한 정보들을 얻을 수 있다
    • 호스트 단위 메트릭
      • CPU, 메모리, 디스크IO 에 관한 메트릭
    • 종합 메트릭
      • DB 계층의 성능, Cache 계층의 성능
    • 핵심 비즈니스 메트릭
      • DAU (Daily Active User) , Retention (재방문) 등

데이터베이스의 규모 확장

  • 데이터베이스에 부하가 많이 걸리면 증설을 검토해봐야 한다
  • 수직적 확장
    • 하드웨어 성능을 끌어올리는 것을 말한다
    • SPOF 위험이 있다
    • 수직적 확장에는 물리적인 한계가 있다
    • 비용이 많이든다
  • 수평적 확장
    • 샤딩
      • 샤딩은 대규모 인터페이스를 샤드 라고 부르는 작은 단위로 분할하는 기술이다
      • 각 샤드는 동일한 스키마를 공유하지만, 보관되는 데이터는 중복이 없어야한다
      • 해시 함수를 사용하여 특정 id가 보관 될 샤드를 결정한다
        • 해시함수 예시 : user_id % 4 ==> user_id 1 = 1번 샤드 , user_id 2 = 2번 샤드.... user_id 5 = 1번 샤드
      • 샤딩 키 를 정하는 것이 가장 중요하다
        • 샤딩 키는 데이터가 어떻게 분산될 지를 정하며, 하나 이상의 컬럼으로 구성 되어야 한다
        • 샤딩 키를 통해 올바른 DB 에 질의를 보낼 수 있기에 효율을 높일 수 있다
        • 샤딩 키를 정할때는 데이터가 고르게 분산될 수 있도록 구성하는 것이 중요하다
          • 예를 들면 특정 샤드에 트래픽이 몰리는 환경을 구성하면 안된다.
            • 1번샤드 : 유명인 팔로워, 2번샤드 : 신입 유투버 팔로워 --> 와 같은 샤딩 키는 1번 샤드에 트래픽이 몰리는 결과를 초래할 수 있다
        • 특정 샤드에 트래픽이 몰리면 재 샤딩을 할 수 있다
          • 샤드 키를 계산하는 함수를 변경하고 데이터를 재배치 해야한다
      • 하나의 DB를 여러 샤드로 쪼개고 나면 여러 샤드에 걸친 데이터를 조인하기 힘들어진다
        • 데이터베이스를 비정규화 하여 하나의 테이블에서 질의가 수행될 수 있도록 개선할 수 있다

백만 사용자 그 이상

  • 시스템 규모를 확장하는 것은 지속적이고, 반복적인 과정이다

결론 및 정리

  1. 웹 계층무상태 계층으로 만든다
  2. 모든 계층다중화를 도입한다
  3. 가능한 한 많은 데이터를 캐시하자
  4. 여러 데이터 센터지원할 것을 권장한다
  5. 정적인 컨텐츠CDN을 통해 서비스하자
  6. 데이터 계층샤딩을 통해 그 규모를 수평적으로 확장할 것을 권장한다
  7. 각 계층독립적인 서비스분할하자
  8. 시스템지속적으로 모니터링하고, 자동화 도구들을 이용하자
반응형

댓글