7 minute read

서론

대규모 사용자를 위한 시스템 설계는 현대 기술의 핵심 과제 중 하나입니다. 사용자 수가 많을수록 이용자들의 요구를 수용하고 빠른 응답을 제공하는 것이 중요합니다. 이를 위해서는 지속적인 개선과 성능 최적화가 필수적입니다. Alex Xu의 System Interview를 참고하여 작성되었습니다.

가장 기초적인 단일 서버를 설계 해보자

간단한 시스템의 경우 모든 컴포넌트가 하나의 서버에서 실행될 수 있습니다. 아래는 기본적인 단일 서버 시스템의 구성을 보여주는 다이어그램입니다.

Untitled Diagram drawio (2)

어떤 데이터베이스를 사용할 것인가?

데이터베이스 선택은 시스템의 성능과 효율성에 큰 영향을 미칩니다. 대부분의 경우, 관계형 데이터베이스와 NoSQL 데이터베이스 중에서 선택해야 합니다.

RDBMS: 관계형 데이터 베이스

  • MySQL, Oracle DB, PostgreSQL 등이 있습니다.
  • 자료를 테이블과 열, 컬럼으로 표현하며, Join을 통해 여러 관계를 합칠 수 있습니다.

NoSQL: 비 관계형 데이터 베이스

  • MongoDB, DynamoDB, Cassandra 등이 있습니다.
  • 키-값 저장소, 그래프 저장소, 칼럼 저장소, 문서 저장소 등으로 구분됩니다.
  • Join 연산을 지원하지 않지만, 대량의 데이터를 저장하고 빠른 응답 시간을 제공하는 데 특화되어 있습니다.

데이터베이스 선택은 다음과 같은 상황에서 NoSQL이 유리할 수 있습니다:

  • 아주 낮은 응답 지연 시간이 필요한 경우
  • 다루는 데이터가 비정형이거나 다양한 형식을 가질 때
  • 데이터를 직렬화하거나 역직렬화할 수 있으면 충분한 경우
  • 대량의 데이터를 저장하고 효율적으로 처리해야 할 때

규모를 확장해보자: 수직적 규모 확장 vs 수평적 규모 확장

서버 확장은 수직적 확장(Vertical Scaling)과 수평적 확장(Horizontal Scaling) 두 가지 방법으로 나뉩니다.

수직적 확장(Vertical Scaling)

단일 서버의 성능을 향상시키기 위해 해당 서버의 하드웨어 사양을 업그레이드하는 방식입니다. 즉, 높은 사양의 서버로 스케일 업하는 것을 의미합니다.

  • 장점:
    • 단일 서버에서의 구현이 비교적 간단합니다.
    • 서버에 유입되는 트래픽이 적을 때 효과적입니다.
  • 단점:
    • 성능 증가에 한계가 있습니다. 서버의 CPU나 메모리를 무한정으로 증설할 수 없습니다.
    • 비용이 선형적으로 증가하는 것보다 더 빠르게 증가합니다.
    • 단일 서버에 장애가 발생하면 전체 서비스가 중단될 수 있습니다.

수평적 확장 (Horizontal Scaling)

서버의 대수를 증가시켜 트래픽을 여러 서버로 분산하는 방식입니다. 다수의 서버로 스케일 아웃하는 것을 의미합니다.

  • 장점:
    • 성능 증가에 한계가 적습니다. 필요에 따라 서버를 추가하여 확장할 수 있습니다.
    • 단일 서버에 장애가 발생해도 다른 서버가 계속 서비스를 제공할 수 있습니다.
  • 단점:
    • 구현이 복잡할 수 있습니다.
    • 서버 간의 동기화와 데이터 일관성을 관리해야 합니다.

웹 계층에서의 다중화(로드밸런서)

앞서 설계에서는 웹 서버와 사용자 간의 직접적인 연결이 있어, 서버 다운 시 사용자에게 서비스를 제공할 수 없거나 응답 속도가 느려질 수 있습니다. 이러한 문제를 해결하기 위해 로드밸런서를 도입하는 것이 최선입니다.

lb

로드밸런서는 웹 서버와 사용자 간의 연결을 관리하며, 이를 통해 서버에 대한 트래픽을 균형 있게 분산시킵니다. 이는 서버에 발생하는 과부하를 방지하고 응답 시간을 최적화하여 사용자 경험을 향상시킵니다. 위의 그림에서 볼 수 있듯이, 사용자는 로드 밸런서의 공개 IP 주소를 통해 서비스에 접속할 수 있습니다. 이 과정에서 서버 간 통신에는 사설 IP 주소가 사용되어 더 나은 보안을 제공합니다. 이 사설 IP 주소는 인터넷을 통한 외부 접속이 불가능하며, 같은 네트워크 내에서만 통신이 이루어집니다.

로드밸런서는 한 서버에 장애가 발생했을 때 자동으로 다른 서버로 트래픽을 전환하여 서비스의 지속성을 유지합니다. 이를 통해 웹 서비스의 가용성과 안정성을 향상시킬 수 있습니다.

데이터 계층에서의 다중화

데이터 계층에서의 다중화는 데이터의 복제와 분산을 의미합니다. 주로 사용되는 방식 중 하나는 주-부(Master-Slave) 관계 설정입니다. 이 구성에서 주 서버는 쓰기 작업을 처리하고, 부 서버는 주 서버의 데이터를 복제하여 읽기 작업만을 처리합니다.

_db drawio

주 서버는 insert, delete, update 와 같은 쓰기 작업을 수행합니다. 부 서버는 읽기 작업을 처리하기 위해 마스터 서버의 데이터를 복제하여 자체적으로 읽기 요청에 응답합니다. 이러한 구성은 데이터의 안정성과 가용성을 향상시키며, 읽기 작업을 분산시켜 전체 시스템의 성능을 향상시킵니다. 대부분의 애플리케이션에서는 읽기 연산이 쓰기 연산보다 더 많이 발생하기 때문에, 이러한 다중화 구성은 데이터베이스 에서 읽기 작업을 효율적으로 처리하기 위한 중요한 전략 입니다.

응답시간을 개선해보자

응답 시간을 개선하는 데에 캐시와 CDN(Content Delivery Network)가 매우 효과적인 도구입니다. 캐시는 자주 참조되는 데이터를 저장하여 동일한 요청에 대해 빠른 응답을 가능케 합니다.

또한, 정적인 콘텐츠를 CDN으로 옮기면 전 세계의 사용자에게 더 빠르게 콘텐츠를 제공할 수 있습니다. CDN은 지리적으로 분산된 서버를 통해 사용자에게 가장 가까운 위치에서 콘텐츠를 제공함으로써 응답 시간을 크게 개선시켜줍니다.

캐시

캐시는 데이터를 잠시 보관하여 데이터베이스 부하를 줄이고 읽기 작업의 성능을 향상시킵니다. 이는 읽기 작업이 많은 애플리케이션에서 특히 유용하며, 적절한 캐싱 전략을 선택하면 데이터 일관성과 성능을 균형있게 유지할 수 있습니다.

캐시 사용시 고려해야 할 사항

  • 캐시의 적합성:
    • 데이터 액세스 패턴을 고려하여 캐시 사용 여부 결정.
    • 읽기가 빈번한 데이터나 자주 변경되지 않는 데이터에 유용.
    • 빈번한 쓰기 작업이 있는 경우 캐시 사용은 부작용을 일으킬 수 있음.
  • 캐시에 보관된 데이터는 어떻게 만료되는가?
    • 데이터의 유효성 유지를 위해 만료 기간 설정.
    • 시간 기반 만료, 데이터 변경 시 만료, 자동 갱신 등의 정책을 고려.
  • 일관성은 어떻게 유지되는가?
    • 캐시와 원본 데이터의 동기화 방법을 결정하여 일관성 유지.
  • 장애에는 어떻게 대처할 것인가?
    • 캐시 실패 시 원본 데이터베이스로부터 데이터를 다시 로드하는 등의 대응 방안 마련.
    • 여러 지역에 걸쳐 캐시 서버를 분산.
  • 데이터 방출 정책은 무엇인가?
    • 캐시 메모리가 가득 찼을 때 어떤 데이터를 제거할지 결정.
    • Least Recently Used (LRU), Least Frequently Used (LFU) 등의 알고리즘을 사용하여 데이터 방출..

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

CDN은 정적 콘텐츠를 더 빠르고 안정적으로 전송하기 위한 지리적으로 분산된 서버 네트워크입니다. 사용자에게 가장 가까운 서버를 통해 콘텐츠를 전달함으로써 트래픽 처리와 서버 부하를 줄여줍니다. 주로 이미지, 비디오, CSS, JavaScript 파일과 같은 정적 콘텐츠를 캐시하여 사용자가 더 빠르게 액세스할 수 있도록 지원합니다. 이는 웹사이트 성능을 향상시키고 로딩 시간을 단축하여 사용자 경험을 최적화하는 데 도움을 줍니다.

CDN 사용시 고려해아 할 사항

  • 적절한 만료 시한 설정: CDN에서 콘텐츠를 얼마나 오랫동안 유지할지 결정하는 것이 중요합니다. 이는 캐시된 콘텐츠의 만료 기간을 설정하여 조절할 수 있습니다. 만료 기간 설정을 통해 새로운 콘텐츠로 업데이트되거나 더 이상 필요하지 않는 콘텐츠가 캐시되지 않도록 관리할 수 있습니다.
  • CDN 장애에 대한 대처 방안: CDN 장애에는 여러 가지 원인이 있을 수 있습니다. 이에 대비하여 다중 CDN을 사용하거나, CDN 공급자가 제공하는 내결함성 기능을 활용하여 장애 시 대체 경로를 설정할 수 있습니다

cache-cdn

위의 그림은 CDN과 캐시가 추가된 설계이다. 이와 같은 변경 사항은 다음과 같은 측면에서 영향을 미친다.

  1. 성능 개선: CDN을 활용하여 정적 콘텐츠를 제공함으로써 사용자들은 빠르게 콘텐츠에 접근할 수 있습니다. 지역에 가까운 서버를 활용함으로써 로딩 시간을 최소화하고, 사용자 경험을 향상시킵니다.
  2. 서버 부하 감소: 캐시는 데이터베이스로의 요청을 줄임으로써 데이터베이스 서버의 부하를 감소시킵니다. 이는 데이터베이스 서버의 성능을 최적화하고, 웹사이트나 애플리케이션의 응답 시간을 향상시켜줍니다.

웹 계층을 수평적으로 확장하는법(무상태 웹 계층)

웹 계층을 수평적으로 확장하는 무상태 아키텍처를 구현하는 방법은 상태 정보를 웹 서버에서 분리하고 공유 저장소에 저장하여 각 웹 서버가 필요한 상태 정보를 필요할 때 공유 저장소에서 가져오는 것입니다.

  • 웹 계층에서 사용자 세션 데이터와 같은 상태 정보를 관계형 DB, NoSQL, 혹은 memcached/Redis와 같은 저장소로 이동합니다.

무상태 아키텍처 예시

Untitled Diagram-Page-5 drawio

이러한 구조는 단순하면서도 안정적이다. HTTP 요청은 어떤 웹 서버로든 전달될 수 있고, 웹 서버는 필요시에만 공유 저장소로부터 상태정보를 가져올수 있다. 상태 정보는 웹서버와 물리적으로 분리되어 있기 때문에 트래픽이 증가하거나 서비스가 확장되더라도 쉽게 시스템 규모를 확장할 수 있다.

Untitled Diagram-Page-6 drawio

위의 설계는 무상태 웹 계층을 위한 구조로, 공유 저장소를 추가하여 세션 데이터를 분리했습니다. 이를 통해 웹 계층은 세션 데이터를 관리하지 않고 클라이언트의 요청을 처리하며, 필요에 따라 공유 저장소에서 세션 데이터를 가져옵니다. 세션 데이터를 분리함으로써 웹 서버를 자동으로 확장하거나 축소할 수 있습니다. 트래픽 증가 시 자동으로 새로운 웹 서버를 추가하여 부하를 분산하고, 트래픽 감소 시 불필요한 서버를 자동으로 삭제함으로써 유연하게 대응할 수 있습니다.

데이터 센터

글로벌 서비스를 위해 여러 데이터 센터를 지원해야 하는 경우, 사용자들이 전 세계 어디에서든 쾌적한 경험을 제공하기 위해 지리적 라우팅을 활용합니다. 지리적 라우팅은 사용자들을 가장 가까운 데이터 센터로 안내하여 네트워크 지연을 최소화하고 빠른 응답 속도를 제공합니다. 또한, 특정 데이터 센터에 장애가 발생했을 때 모든 트래픽을 다른 정상적인 데이터 센터로 전송하여 서비스의 가용성을 유지하는 방법을 고려해야 합니다.

Untitled Diagram-Page-7 drawio

다중 데이터 센터 아키텍처를 구축하는 과정에서 고려해야할 사항이 있습니다.

  1. 트래픽 우회:
    • 데이터 센터 중 하나에서 장애가 발생했을 때 해당 데이터 센터로 향하는 트래픽을 다른 정상적인 데이터 센터로 안전하게 전송해야 합니다. 이를 위해 효율적이고 신속한 트래픽 우회 기술이 필요합니다.
  2. 데이터 동기화:
    • 각 데이터 센터마다 별도의 데이터베이스를 유지하고 있기 때문에, 이 데이터들을 실시간으로 동기화하여 일관성을 유지해야 합니다. 데이터 센터 간에 데이터를 동기화하고 동일한 정보를 보장하는 기술적인 해결책이 필요합니다.
  3. 테스트/배포:
    • 새로운 기능을 테스트하고 배포하기 전에 각 데이터 센터에서의 테스트와 배포 과정을 철저히 거쳐야 합니다. 이를 통해 안정적이고 일관된 서비스를 제공할 수 있도록 기술적 난제를 해결해야 합니다.

메시지 큐

  1. 메시지 큐: image

메세지 큐는 비동기 통신 매체로, 일단 보관된 메시지는 소비자가 꺼낼 때까지 안전하게 보관됩니다.

장점:

  • 느슨한 결합성: 서비스 또는 서버간의 결합이 느슨해지므로, 규모 확장성이 있는 안정적인 어플리케이션을 만들 수 있다.
  • 안정성: 생산자는 소비자 프로세스가 다운되어도 메시지를 발행할 수 있고, 그 반대의 경우도 가능하다.

사용사례:

  • 알림 및 푸시 서비스
  • 이메일 발송
  • 이미지 보정
  1. 이벤트 큐:

이벤트 큐는 메시지 큐와는 조금 다르게 작동합니다. 메시지 큐와 달리 한 번 읽은 데이터가 즉시 삭제되지 않습니다. 이벤트 기반 마이크로서비스 아키텍처를 구현하는 데 널리 사용됩니다.

[특징]

  • 단일 진실 공급원: 이벤트 큐에서는 단일한 소스로부터 이벤트를 받아들입니다.
  • 재처리 가능: 장애가 일어난 시점부터 다시 처리할 수 있습니다.
  • 대량의 데이터 효율적 처리: 많은 양의 실시간 데이터를 효율적으로 처리할 수 있습니다.

데이터베이스의 규모 확장

데이트베이스에 저장되는 데이터가 많아질수록 부하도 증가하게 되는데, 이를 위한 두 가지 주요한 확장 방법이 있다.

수직적 확장 스케일업으로, 이 방법은 단일 서버의 성능을 향상시키는 방법입니다. 더 많은 고성능 자원을 추가하여 부하를 줄이는 것입니다.

단점:

  • 하드웨어 한계: 무한히 자원을 추가할 수 없다.
  • SPOF(Single Point of Failure): 단일 서버 장애시 전체 시스템 다운
  • 고비용: 고성능 서버일수록 비쌈

수평적 확장 수평적 확장은 더 많은 서버를 추가하여 성능을 향상시키는 방법입니다. 여기서 중요한 개념이 “샤딩(Sharding)”입니다. image

  • 샤딩: 대규모 데이터베이스를 작은 단위인 샤드로 분할하는 것을 의미합니다. 각 샤드는 같은 스키마를 사용하지만 데이터는 중복되지 않습니다.

image

위 예제처럼 user_id % 4 를 사용하여 데이터를 보관되는 샤드를 정한다면, 그 결과로 0이면 0번 샤드, 1이면 1번 샤드에 보관 된다.

단점

  • 여러 샤드에 걸친 데이터를 조인하기가 매우 어렵다.
  • 핫스팟 키 문제: 특정 샤드에 쿼리가 집중이 될 수 있다.
  • 데이터 재샤딩의 어려움

결론

시스템을 규모 확장하기 위해 고려해야 할 몇 가지 기법들이 있습니다:

  • 무상태 웹 계층: 상태를 서버에 유지하지 않고 클라이언트와의 상호작용을 최소화하여 웹 계층을 무상태로 유지합니다.
  • 다중화(Multiplication) 도입: 모든 계층에서 다중화를 고려하여, 시스템의 안정성과 가용성을 높입니다.
  • 캐싱 활용: 가능한 많은 데이터를 캐시하여 데이터 액세스 속도를 향상시킵니다.
  • 다중 데이터 센터 지원: 여러 데이터 센터를 활용하여 시스템의 이중화를 도입하고, 가용성을 높입니다.
  • CDN 활용: 정적 콘텐츠를 Content Delivery Network(CDN)을 통해 서비스하여 전 세계적으로 빠른 전송을 보장합니다.
  • 데이터베이스 샤딩: 대규모 데이터베이스를 관리하기 위해 데이터베이스 샤딩을 도입하여 규모를 확장합니다.
  • 계층적 분할: 각 계층을 독립적인 서비스로 분할하여 유연성과 확장성을 향상시킵니다.
  • 모니터링 및 자동화: 시스템을 지속적으로 모니터링하고, 자동화된 도구를 활용하여 효율적인 관리와 유지보수를 지원합니다.

이런 기법들을 통해 시스템이 규모를 키우면서 안정성, 성능, 확장성을 유지할 수 있습니다.

Leave a comment