새소식

Architecture

[Architecture]대규모 애플리케이션을 위한 아키텍처 설계 가이드

  • -

개요

데이터베이스 선택, 애플리케이션의 확장, 로드밸런싱, 캐싱, CDN 활용, 데이터베이스 샤딩 등의 전략을 통해 효율적이고 확장 가능한 웹 시스템 아키텍처를 설계할 수 있습니다.

요약: 사용자 수에 따른 규모 확장성

  1. 웹 계층은 Stateless해야 합니다.
    • 이는 시스템이 더 많은 사용자와 트래픽을 수용할 수 있도록 만듭니다.
  2. 모든 계층에 다중화를 도입합니다.
    • 이는 시스템의 부하를 분산시키고 가용성을 높입니다.
  3. 가능한 한 많은 데이터를 캐시합니다.
    • 이는 응답 시간을 단축하고 시스템의 전반적인 성능을 향상합니다.
  4. 정적 콘텐츠는 CDN을 통해 서비스합니다.
    • 이는 전 세계적으로 빠른 콘텐츠 전달을 가능하게 합니다.
  5. 데이터 계층은 샤딩을 통해 확장합니다.
    • 이는 데이터 관리를 보다 효율적으로 만듭니다.
  6. 각 계층을 독립적 서비스로 분할합니다.
    • 이는 유지 관리와 확장성을 개선합니다.
  7. 시스템을 지속적으로 모니터링하고 자동화 도구를 활용합니다.
    • 이는 문제를 빠르게 식별하고 해결하는 데 도움이 됩니다.

1. 웹 계층과 데이터 계층에 대한 이해

데이터베이스 선택하기

어떤 데이터베이스를 사용해야 할까?

RDB vs NoSQL:

  • 과거엔 주로 관계형 데이터베이스(RDB)를 사용했지만, 최근에는 NoSQL이 성능, 기능성, 비즈니스 요구사항에 따라 인기를 얻고 있습니다.
  • RDB는 HA(고가용성)와 장애 복구(Failover)를 위해 Source-Replica 구조를 가질 수 있습니다.
  • NoSQL은 낮은 응답 지연시간, 비정형 데이터 처리, 대량 데이터 저장 등의 장점을 제공합니다.

수평적 규모 확장 활용

Scale Up(수직적 확장):

  • 자동 복구나 다중화 방안을 제공하지 않으며, 장애 발생 시 서비스 중단이 있을 수 있습니다.

Scale Out(수평적 확장):

  • 새로운 서버를 추가하여 자원을 확장하는 방법입니다.
  • 다중화를 통한 HA와 Failover로 비즈니스 안정성을 향상합니다.

로드밸런서 사용

  • 부하 분산을 위해 트래픽을 분산시키며, 가용성을 향상합니다.
  • 앞단에 로드밸런서를 두고 연결되는 웹 서버와 통신하기 위해 사설 주소를 사용할 수 있습니다.

데이터베이스 다중화

  • 주로 Source-Replica 구조를 사용하여, Source에는 원본 데이터, Replica에는 데이터 사본을 저장합니다.
  • Replica는 주로 읽기 연산에 집중되며, 병렬 처리로 성능이 향상됩니다.
  • 데이터의 안정성과 가용성을 위해 다양한 지역에 데이터를 복제합니다.
  • 다중화를 통해 Source 서버에 문제가 발생하더라도 다른 서버를 승격시켜 서비스의 지속성을 보장합니다.
  • 복제 지연 문제는 복구 스크립트나 다중 마스터 전략을 도입하여 해결할 수 있습니다.

위 내용이 적용된 아키텍처

동작

  1. 사용자는 DNS로부터 LB의 IP 주소를 받는다.
  2. 사용자는 해당 IP 주소를 사용해 LB에 접속한다.
  3. HTTP 요청은 웹 계층의 서버에 분산되어 전달된다.
  4. 웹 서버는 사용자의 데이터를 부 데이터베이스 서버에서 읽는다.
  5. 웹 서버는 데이터 변경 연산은 주 데이터베이스로 전달한다. (데이터 추가, 삭제, 갱신 등)

2. 응답시간 개선하기

응답시간은 캐시를 붙이고 정적 콘텐츠를 CDN로 옮기면 개선할 수 있다.

캐시

캐시 계층

캐시는 비용이 많이 드는 연산 결과, 정적 데이터 또는 자주 참조되는 데이터를 메모리에 저장하여 접근 속도를 빠르게 해 줍니다.

서버와 데이터베이스 중간에 위치시켜서 이전에 조회했던 데이터에 대해서는 데이터베이스에서 조회하지 않고, 캐시에서 바로 데이터를 가져와서 응답함으로써 성능 개선데이터베이스의 부하를 줄일 수 있고, 캐시 계층의 규모를 독립적으로 확장시키는 것도 가능해집니다.

캐시 사용 시 유의할 점

캐시 서버를 사용할 때는 성능 향상을 위해 필수적으로 고려해야 하는 여러 중요한 요소들이 있습니다. 캐시는 자주 요청되는 데이터를 빠르게 제공하여 서버 부하를 줄이고, 응답 시간을 단축시키는 역할을 합니다. 그러나 적절하게 관리되지 않으면, 오히려 성능 문제를 야기할 수도 있습니다. 다음은 캐시 서버 사용 시 유의해야 할 주요 사항들입니다:

1. 캐시 만료 정책

  • 만료 시간 설정 (TTL): 캐시 데이터의 TTL(Time To Live)을 설정하여 메모리 부족 상황을 예방할 수 있습니다. 적절한 TTL 값을 설정하여 데이터가 자동으로 제거되도록 관리합니다.
  • LRU, FIFO 정책 고려: 캐시에서 데이터를 제거하는 정책을 선택하여 적용합니다.

2. 데이터 방출 정책

  • 캐시가 가득 차게 되면 새로운 데이터를 캐시에 추가하기 위해 기존의 데이터를 방출해야 하는데, 이를 위해 다양한 데이터 방출(또는 제거) 정책이 존재합니다.
  • 캐시 데이터 방출 정책의 선택: 캐시 데이터 방출 정책을 선택할 때는 애플리케이션의 특성과 요구사항을 고려해야 합니다. 예를 들어, 실시간성이 중요한 애플리케이션의 경우 TTL이나 LRU가 효과적일 수 있으며, 접근 빈도가 중요한 경우에는 LFU가 적합할 수 있습니다.

3. 캐시 일관성

  • 데이터 동기화: 데이터베이스와 캐시 간 일관성 유지를 위해 트랜잭션 관리가 중요합니다. 데이터베이스 업데이트와 캐시 업데이트를 동시에 처리하여 일관성을 보장해야 합니다.
  • 병렬 처리 유의: 다중 서버 환경에서의 캐시 일관성 유지에 주의합니다.

4. 캐시 크기 및 분할

  • 적절한 캐시 크기 설정: 메모리 자원 활용 및 효율적인 캐시 관리를 위해 적절한 크기를 설정합니다.
  • 캐시 분할: 다양한 데이터 유형에 대해 서로 다른 캐시 영역을 사용합니다.

5. 보안 고려사항

  • 암호화된 데이터 캐싱: 민감한 데이터는 암호화하여 캐시 합니다.
  • 접근 제어: 캐시 데이터에 대한 접근을 엄격히 제어합니다.

6. 오버헤드 및 성능 모니터링

  • 캐시 오버헤드: 캐시 미스율을 모니터링하고 캐시 구조를 최적화합니다.
  • 성능 모니터링: 캐시의 성능을 지속적으로 관찰하고 필요에 따라 조정합니다.

7. 백업 및 재난 복구 계획

  • 캐시 데이터 백업: 중요한 캐시 데이터의 정기적 백업을 수행합니다.
  • 재난 복구 계획: 캐시 서버 장애 대비 복구 계획을 수립합니다.

8. 확장성과 부하 분산

  • 확장 가능한 캐시 구조: 증가하는 사용량에 대응하기 위해 캐시 시스템의 확장성을 고려합니다.
  • 부하 분산: 여러 캐시 인스턴스를 통해 부하를 분산시킵니다.

추가 설명

캐시 데이터 방출 정책

1. Least Recently Used (LRU):

  • 작동 원리: 가장 오랫동안 사용되지 않은 항목을 캐시에서 제거합니다.
  • 적용 사례: 사용 빈도가 낮은 데이터를 제거하여, 자주 접근되는 데이터를 캐시에 유지하고자 할 때 유용합니다.

2. First In, First Out (FIFO):

  • 작동 원리: 캐시에 가장 먼저 들어온 데이터를 가장 먼저 제거합니다.
  • 적용 사례: 데이터가 동일한 시간 동안 캐시에 머물러야 하는 경우에 적합합니다.

3. Least Frequently Used (LFU):

  • 작동 원리: 가장 적게 사용된 항목을 제거합니다.
  • 적용 사례: 사용 빈도가 낮은 데이터보다는 사용 빈도가 높은 데이터를 캐시에 유지하고자 할 때 적합합니다.

4. Random Replacement (RR):

  • 작동 원리: 무작위로 항목을 선택하여 제거합니다.
  • 적용 사례: 간단한 구현이 필요하거나, 다른 정책들이 제공하는 이점이 크게 중요하지 않은 경우에 사용됩니다.

4. Time-to-live (TTL):

  • 작동 원리: 설정된 시간이 지난 후 데이터를 제거합니다.
  • 적용 사례: 데이터가 일정 시간 동안만 유효해야 하는 경우에 적합합니다.

운영 시 필요한 모니터링 지표

  1. 캐시 히트율(Cache Hit Rate)
    • ElastiCache for Redis의 캐시 히트율을 모니터링하여 캐시의 효율성을 평가합니다. CloudWatch 메트릭스를 통해 이를 확인할 수 있습니다.
  2. 캐시 미스율(Cache Miss Rate)
    • 캐시 미스율도 중요한 지표로, 캐시 전략의 개선 여부를 판단하는 데 도움이 됩니다. CloudWatch를 통해 이 지표를 확인할 수 있습니다.
  3. 응답 시간(Response Time)
    • AWS Redis의 응답 시간을 모니터링하여 캐시 시스템의 성능을 평가합니다. 빠른 응답 시간은 시스템의 효율성을 나타냅니다.
  4. 메모리 사용량(Memory Usage)
    • ElastiCache for Redis의 메모리 사용량을 주시하여 메모리 부족 상황을 사전에 방지합니다. CloudWatch 메트릭스를 통해 메모리 사용량을 확인할 수 있습니다.
  5. 네트워크 I/O
    • 네트워크 입출력은 Redis 클러스터의 성능과 직결되므로, CloudWatch를 통해 이를 모니터링합니다.

CDN

정적 콘텐츠 전송하는 데 쓰이는, 지리적으로 분산된 서버의 네트워크입니다.

CDN 사용 시 고려해야 할 사항

비용

CDN 서비스는 대체로 사용량 기반으로 비용이 청구되기 때문에 예상 트래픽과 데이터 전송량을 사전에 평가해야 합니다.

적절한 만료 시한 설정

CDN은 콘텐츠를 캐싱하여 빠른 제공을 목표로 하므로, 캐시 된 콘텐츠의 유효성 기간을 설정하는 것이 중요합니다.. 이 만료 시간을 너무 길게 설정하면 콘텐츠 업데이트 시 사용자들이 최신 버전의 콘텐츠를 볼 수 없을 수 있습니다.

CDN 장애에 대한 대처 방안

때때로 서비스 중단이나 지연이 발생할 수 있습니다. 이런 경우를 대비하여 CDN 서비스가 중단되었을 때 원본 서버로 자동으로 전환될 수 있도록 백업 전략을 갖추는 것이 중요합니다.

콘텐츠 무효화

CDN에서 캐시된 콘텐츠를 무효화하는 것은 콘텐츠의 즉각적인 업데이트를 보장하기 위해 필요합니다. 예를 들어, 웹사이트의 메인 페이지 이미지나 중요한 공지사항을 업데이트했을 때, 이 변경사항을 사용자에게 즉시 반영하기 위해서는 CDN에서 해당 콘텐츠의 캐시를 무효화해야 합니다.

CDN과 캐시가 추가된 설계의 장점

정적 콘텐츠는 CDN을 통해 제공하여 더 나은 성능을 보장합니다. 캐시가 데이터베이스의 부하를 줄여줍니다.

3. 무상태(Stateless) 웹 계층의 이해

웹 서비스를 설계할 때 확장성은 매우 중요한 고려 사항입니다. 서비스가 성장하고 사용자가 늘어남에 따라 시스템이 이를 원활하게 처리할 수 있어야 합니다. 이를 위한 핵심 원칙 중 하나가 바로 '무상태 웹 계층'의 개념입니다.

무상태 웹 계층이란?

'무상태(Stateless)'란 말 그대로 서버가 사용자의 상태 정보를 기억하지 않는 것을 의미합니다. 즉, 각 요청은 독립적이며, 이전 요청의 정보를 서버가 저장하고 있지 않습니다. 서버는 오직 받은 요청만을 처리하고, 필요한 정보는 요청과 함께 전달되어야 합니다.

확장성을 위한 핵심

무상태 웹 계층은 확장성에 매우 유리합니다. 서버는 각 요청을 독립적으로 처리하기 때문에, 새로운 서버 인스턴스를 추가하는 것만으로 시스템의 처리 능력을 쉽게 확장할 수 있습니다. 이는 '수평적 확장'이라고 하며, 시스템을 간단히 확장하고 유지 관리할 수 있는 중요한 방법입니다.

상태 정보의 관리

무상태 아키텍처에서는 사용자의 상태 정보나 세션 데이터와 같은 중요 정보를 다른 저장소에 보관합니다. 이러한 저장소로는 RDBMS, NoSQL 데이터베이스, 또는 키-값 저장소인 Redis 등이 사용될 수 있습니다. 이 저장소들은 고가용성과 빠른 접근을 제공하여, 필요할 때마다 즉시 상태 정보를 검색할 수 있게 해 줍니다.

시스템의 컴포넌트 분리

대규모 시스템을 설계할 때는 각 컴포넌트를 분리하여 독립적으로 확장할 수 있어야 합니다. 무상태 웹 계층은 이러한 분리를 용이하게 하여, 웹 서버, 애플리케이션 서버, 데이터베이스 서버 등 각각을 독립적으로 스케일링할 수 있게 합니다.

무상태 웹 계층의 이점

  1. 확장성: 서버를 추가하거나 제거하기 쉬워, 시스템을 유연하게 확장할 수 있습니다.
  2. 부하 분산: 각 요청이 독립적이므로, 여러 서버에 요청을 균등하게 분산시킬 수 있습니다.
  3. 복원력: 하나의 서버에 문제가 생겨도, 다른 서버가 요청을 처리할 수 있어 시스템의 전체적인 안정성이 향상됩니다.
  4. 간소화된 관리: 서버 상태를 추적할 필요가 없으므로 시스템 관리가 간편해집니다.

결론

무상태 웹 계층은 대규모 웹 서비스를 설계할 때 필수적인 요소입니다. 이를 통해 시스템의 확장성, 관리 용이성, 안정성을 크게 향상할 수 있습니다. 초보자들이라도 이 개념을 이해하고 적용한다면, 더 강력하고 효율적인 웹 서비스를 구축하는 데 큰 도움이 될 것입니다.

메시지 큐

메시지 큐란 무엇인가?

메시지 큐는 컴포넌트 간 메시지를 전달하는 데 사용되는 시스템으로, 다양한 부분에서 독립적으로 동작하는 애플리케이션 간의 비동기 통신을 가능하게 합니다. 간단히 말해, 한 시스템(발행자)이 메시지를 '큐'에 보내면, 다른 시스템(구독자)이 그 메시지를 '큐'에서 가져와 처리합니다.

메시지 큐의 핵심 기능

  1. 비동기 통신 지원: 메시지 큐는 시스템 간 비동기적으로 데이터를 교환할 수 있게 해 주어, 한 시스템이 다른 시스템의 응답을 기다리지 않고도 작업을 계속 진행할 수 있습니다.
  2. 무손실 보장: 메시지 큐는 메시지를 안전하게 저장하고 전달함으로써, 네트워크 문제나 시스템 장애가 발생해도 메시지가 손실되지 않도록 보장합니다.
  3. 탄력적인 통신: 시스템 부하가 증가해도 메시지 큐를 통해 메시지를 일정하게 처리할 수 있으며, 피크 시간에 발생하는 부하를 관리할 수 있습니다.

메시지 큐를 사용하는 이유

  1. 결합도 감소: 서비스 간의 결합도를 낮춤으로써, 하나의 컴포넌트에 문제가 발생해도 전체 시스템에 미치는 영향을 최소화할 수 있습니다.
  2. 확장성 향상: 시스템 간의 의존성이 줄어들어, 각 컴포넌트를 독립적으로 확장하거나 업데이트하기 쉬워집니다.
  3. 부하 분산: 트래픽이 많은 시간에도 메시지 큐를 통해 요청을 고르게 분산시켜, 시스템의 안정성을 유지할 수 있습니다.
  4. 비동기 처리 가능: 서비스가 메시지를 큐에 보낸 후 즉시 다른 작업을 수행할 수 있어, 전체적인 시스템의 효율성이 향상됩니다.

결론

메시지 큐는 시스템을 더 큰 규모로 확장하고자 할 때, 컴포넌트를 효과적으로 분리하고 각기 독립적으로 확장할 수 있도록 하는 핵심적인 전략입니다. 이를 통해 시스템의 안정성, 확장성 및 유연성을 대폭 향상할 수 있으며, 복잡한 시스템 간의 통신을 효율적으로 관리할 수 있습니다. 초보자 분들도 이러한 개념을 이해하고 적용한다면, 더 견고하고 확장 가능한 시스템을 설계하는 데 큰 도움이 될 것입니다.

4. 데이터베이스의 규모 확장

저장할 데이터가 많아지면 데이터베이스를 증설할 방법을 찾아야 합니다. 데이터베이스의 규모를 확장하는 데는 두 가지 방법이 존재합니다: 수직적 확장, 수평적 확장

수직적 확장 (Vertical Scaling)

개념:

수직적 확장은 서버의 CPU, 메모리, 스토리지 같은 하드웨어 자원을 업그레이드하여 성능을 향상하는 방법입니다.

한계:

  • 비용과 한계: 하드웨어 자원에는 물리적 한계가 있으며, 비용도 많이 듭니다.
  • SPOF(Single Point of Failure)로 인한 위험성이 큽니다.
  • 확장성의 한계: 한계에 도달하면 더 이상 성능을 향상할 수 없습니다.

수평적 확장(Sharding)

샤딩(Sharding)이란?

  • 샤딩은 큰 데이터베이스를 작은 단위인 샤드로 분할합니다. 각 샤드는 독립된 데이터베이스 서버에 존재하며, 전체 데이터베이스의 일부를 보유합니다.
  • 이 분할은 데이터베이스의 부하를 여러 서버로 분산시키고, 각 서버의 데이터 처리 및 저장 용량을 최적화합니다.

https://www.youtube.com/watch?app=desktop&v=XP98YCr-iXQ

샤딩 키 (Sharding Key):

  • 샤딩 키는 데이터를 샤드에 분배하는 기준이 되는 속성입니다. 예를 들어, 사용자 ID, 지역 코드, 시간 범위 등이 샤딩 키가 될 수 있습니다.
  • 샤딩 키는 각 데이터 항목을 특정 샤드에 일관되게 할당하므로, 데이터를 검색하거나 업데이트할 때 어느 샤드로 가야 하는지 결정하는 데 중요합니다.

샤딩의 장점

  1. 확장성: 수직적 확장에는 물리적 한계가 있지만, 샤딩을 통해 데이터베이스를 수평적으로 확장할 수 있어 시스템을 더 크게 확장할 수 있습니다.
  2. 성능 향상: 데이터와 트래픽을 여러 샤드에 분산시킴으로써, 단일 서버에 가해지는 부하를 줄이고 응답 시간을 개선할 수 있습니다.
  3. 고가용성: 하나의 샤드에 문제가 발생해도, 다른 샤드는 여전히 동작하기 때문에 전체 시스템의 가용성을 높일 수 있습니다.

샤딩 시 고려해야 할 주요 이슈들

1. 복잡성 증가

  • 샤딩은 데이터베이스 아키텍처의 복잡성을 크게 증가시킵니다. 개발자는 샤드 간 데이터 분배, 트랜잭션 관리, 샤드 간 조인 등 새로운 문제에 대해 고민해야 합니다.

2. 데이터 재샤딩

  • 재샤딩은 한 샤드의 데이터가 너무 많아지거나 불균등하게 분배되었을 때 필요합니다. 재샤딩은 데이터를 새로운 샤드 구성에 맞게 이동시키는 복잡하고 시간이 많이 소요되는 과정입니다.

3. 유명인사 문제 (Hotspot Issue)

  • 특정 샤드에 대한 요청이 집중되는 핫스팟 문제가 발생할 수 있습니다. 예를 들어, 매우 인기 있는 '유명인사'의 데이터가 있는 샤드는 다른 샤드보다 훨씬 더 많은 요청을 받게 되어 성능 병목이 발생할 수 있습니다.

4. 조인과 복잡한 쿼리의 어려움

  • 샤딩된 데이터베이스에서는 여러 샤드에 걸쳐 있는 데이터를 조인하는 것이 매우 어렵습니다. 이로 인해 애플리케이션에서 복잡한 쿼리 로직을 구현해야 할 수 있으며, 이는 성능 저하로 이어질 수 있습니다.

5. 트랜잭션 일관성 관리

  • 여러 샤드에 걸쳐 일관된 트랜잭션을 유지하는 것은 매우 복잡합니다. 분산 트랜잭션은 일반적으로 오버헤드가 크고, 성능을 저하시킬 수 있습니다.

샤딩의 예제: 사용자 데이터 샤딩

상황:

  • 대규모 소셜 미디어 플랫폼이 사용자의 급격한 증가로 인해 데이터베이스 성능 병목을 경험하고 있습니다.

해결 방안:

  • 샤딩 키 선택: 사용자의 지리적 위치 또는 사용자 ID의 해시 값을 샤딩 키로 사용합니다.
  • 데이터 분배: 각 사용자의 데이터는 지리적 위치나 ID에 따라 다른 샤드에 저장됩니다. 이렇게 하면 요청이 여러 샤드에 균등하게 분산되어 각 샤드의 부하가 줄어듭니다.

결과:

  • 시스템은 사용자 증가에 따라 샤드를 추가함으로써 확장할 수 있으며, 각 사용자에 대한 요청은 빠르고 효율적으로 처리됩니다.

 

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

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.