본문 바로가기
학습기록

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

by seongju.lee 2023. 6. 30.

사용자 수가 증가함에 따라 시스템 구조에 어떤 변화를 줘야 하는지에 대해 알아보고자 정리를 한다.

해당 내용은 「가상 면접 사례로 배우는 대규모 시스템 설계 기초」 1장 내용이다.

 

내용을 정리하면서, 중간중간 이해가 어려운 부분에 대해서 다른 포스팅으로 정리하며, 내 머릿속에도 설계에 대한 사고력을 확장시켜 나가고자 한다.

본 내용은 단일 서버부터 시작하여 사용자 수에 따른 시스템 변화를 알아본다.

 

1. 단일 서버

1. 사용자는 도메인명을 이용하여 웹 사이트에 접속한다.
때문에 DNS 질의를 통해 주소변환 과정을 거친다.

2. DNS 조회 결과로 IP주소가 반환.

3. 해당 IP주소로 요청을 보내면

4. 요청을 받은 웹 서버가 클라이언트에게 응답을 반환한다.

 

 

2. 데이터베이스 분리

  • 사용자가 늘어남에 따라서 하나의 서버로는 충분하지 못하는 게 당연하다.
  • 클라이언트의 요청과 같은 트래픽을 처리하는 웹 서버 계층과 데이터베이스를 분리하여 확장 가능성을 열어둔다.
  • 예를 들어, 트래픽이 늘어남에 따라 Web Server를 증설하여 독립적인 확장이 가능하다.

 

2-1. 데이터베이스 선택

  • 어떤 데이터베이스를 선택할 것인가도 고민해봐야할 부분이다.
    • 관계형 데이터베이스: SQL을 사용하여 테이블간의 관계를 맺어 데이터를 가져올 수 있다.
    • 비-관계형 데이터베이스: NoSQL이라고도 부르며, 네 가지 부류로 나눌 수 있다고 한다.
      (키-값 저장소, 그래프 저장소, 칼럼 저장소, 문서 저장소)
  • 언제 어떤 종류의 데이터베이스를 선택해야 하는 지 결정하기 위해서는 두 데이터베이스의 특징을 알아야 하므로
    별도로 정리해야 할 것 같다.

 

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

위에서 웹 서버 계층과 데이터베이스를 분리한 가장 큰 이유는 각 계층별로 독립적인 확장을 하기 위함이다.

그렇다면 확장하는 방법에는 무엇이 있을까? 가장 크게 두 가지로 나뉜다.

  • 수직적 규모 확장(Vertical scaling): 소위 말하는 '스케일-업'이다.
    현재 가용한 서버에 고사양 자원(더 좋은 CPU, 더 많은 RAM)을 추가하는 것을 말한다.
  • 수평적 규모 확장(Horizontal scaling): 소위 말하는 '스케일-아웃'이다.
    양적 확장을 의미하며, 더 많은 서버를 추가하여 성능을 개선하는 것을 말한다.

당연하게도 대규모 애플리케이션을 지원하기 위한 확장법은 수평적 규모 확장 방법이다.

그 이유는 수직적 규모 확장의 한계점 때문인데, 그 한계점은 아래와 같다.

  • 한 대의 서버에 하드웨어 장비를 무한정으로 증설할 방법이 없다.
  • 장애에 대한 복구나 다중화 방안이 없다. 서버 한 대에 장애가 발생하면 시스템이 중단된다.

우선, 웹 서버에 대한 확장을 알아보자.

 

로드밸런서

현재까지 위에서 살펴본 바, 웹 서버는 단 한대만 존재한다. 사용자가 많아지면 동시에 많은 사용자들이 하나의 웹서버에 접속하게 될 것이고 그로 인해, 응답 속도가 느려지거나 접속이 불가해진다.

이 문제를 해결하기 위해서는 웹 서버를 증설하고, 각 웹 서버에 고르게 사용자들이 접속하도록 해야 한다.
이런 식의 해결을 위해 로드밸런서(load balancer)를 도입하는 것이 최선이다.

위 그림을 보면 로드밸런서가 클라이언트의 요청을 웹 서버 1과 웹 서버 2 중, 하나를 선택하여 보냄으로써 분산하는 역할을 담당한다.

클라이언트는 DNS 질의를 통해 로드밸런서의 public IP를 얻고, 해당 IP로 요청을 보낸다.
그리고, 클라이언트의 요청을 받은 로드밸런서는 정해진 알고리즘에 따라 적절히 트래픽을 분산하여 웹 서버로 전달한다.

이때, 로드밸런서가 웹 서버로 트래픽을 전달할 때는 private IP를 사용한다. 보통 더 나은 보안을 위해 같은 네트워크에 속한 서버 간 통신은 사설 IP가 이용된다.

 

이렇게 웹 서버 증설을 통해 부하를 줄였고, 아래와 같은 이점들도 있다.

  1. 장애에 대한 자동복구가 가능하다. (가용성)
    - 서버 1이 다운되면 모든 트래픽이 2로 가긴 하지만, 서비스 자체가 다운되는 일은 방지할 수 있게 되었다.
  2. 현재는 두 대의 웹 서버이지만, 트래픽이 급증하면 웹 서버 계층에 더 많은 서버를 추가하면 된다.
    로드 밸런서가 자동으로 트래픽을 분산하기 때문이다.

지금까지 로드 밸런서를 적극 활용하여 웹 서버 계층의 수평적 확장을 진행했다.

그럼 이제 데이터 계층 또한 부하를 줄이기 위해 다중화를 진행해 보자.

 

데이터베이스 다중화

웹 서버 계층에서 수평적 확장의 이점으로 가용성을 말했다.

데이터베이스도 마찬가지로 장애가 발생했을 때, 다른 DB로 트래픽이 가도록 다중화를 해야 한다.

이러한 데이터베이스 다중화는 Replication을 통해서 이루어지곤 하는데, Replication이란 "한 데이터베이스를 다른 데이터베이스에 동기화하는 것"을 말한다.

위에서 말한 "한 데이터베이스"가 주 데이터베이스가 되고, " 다른 데이터베이스"가 부 데이터베이스가 된다.

그리고 주 데이터베이스에서만 데이터 조작이 가능하며, 부 데이터베이스에서는 읽기 작업만 가능하다.

(대부분의 애플리케이션은 읽기 연산의 비중이 쓰기 연산보다 훨씬 많다.)

 

위와 같이 데이터베이스 다중화를 통해 얻을 수 있는 이점은 아래와 같이 정리 가능하다.

  1. 더 나은 성능: 모든 쓰기 연산은 주 DB로, 읽기 연산은 부 DB로 분산되면서 병렬로 처리 가능한 쿼리가 늘어남에 따라 성능이 향상된다.
  2. 유연한 Scale-out: 부 DB를 추가만 해줌으로써, 급증하는 트래픽에 유연하게 대처가 가능하다.
  3. 안정성: 데이터베이스가 지리적으로 분산되어 있음에 따라 빠른 응답이 가능해지고,
    자연재해 등으로 일부 DB서버가 파괴되어도 데이터는 보존된다.
  4. 가용성: 하나의 DB서버가 장애가 나더라도 다른 서버에 있는 데이터를 이용해서 서비스가 유지된다.
    가용성 측면에서 바라봤을 때, "만약 주 DB가 장애가 나면?"과 같은 상황도 가정해봐야 한다.
    • 주 데이터베이스 서버가 다운된다면?
      • 다른 부 데이터베이스 서버 중 하나가 새로운 주 서버가 될 것이다.
      • 하지만, 부 서버에 보관된 데이터가 주 서버와 비교했을 때, 최신 상태가 아닐 수도 있다.
        이러한 상황에서는 어떤 방식으로 처리되는지 알아봐도 좋을 것 같다.

 

로드밸런서(웹 서버 계층의 Scale-Out)와 Replication(데이터베이스 다중화)을 적용한 모습

전체적인 흐름

  1. 사용자는 DNS 질의를 통해 로드밸런서의 public IP를 얻는다.
  2. 사용자는 로드밸런서에게 요청을 보낸다.
  3. 로드밸런서는 웹 서버 1, 웹 서버 2 중 적절한(부하를 줄이는) 웹 서버로 요청을 전달한다.
    이때, private IP를 통해 전달하게 된다.
  4. 웹 서버는 사용자의 요청 데이터를 부 DB에서 읽는다.
  5. 웹 서버는 데이터 조작에 대한 요청은 주 DB로 전달한다.

 

다음은 응답지연시간(latency)을 줄이기 위해 캐시를 도입할 것이다.

 

캐시

캐시는 값비싼 연산 결과나 자주 참조되는 데이터를 메모리 안에 두고, 뒤이은 요청에서는 보다 빠르게 처리되도록 하는 저장소이다.

애플리케이션은 외부에 있는 데이터베이스를 얼마나 자주 호출하느냐에 따라 크게 좌우되는데, 캐시를 사용하면 그런 문제를 완화할 수 있다.

 

캐시 계층

캐시 계층을 두면 앞서 말한 데이터 접근에 대한 성능이 개선될 뿐만 아니라 데이터베이스의 부하를 줄일 수도 있고, 캐시 계층의 규모를 독립적으로 확장시키는 것도 가능하다.

위와 같이 cache hit(캐시에 데이터가 있는 경우), cache miss(캐시에 데이터가 없어, 데이터베이스에 질의하는 경우)에 따라 요청에 대한 응답을 한다. 이러한 캐시 전략을 읽기 주도형 캐시 전략(read-through caching strategy)라고 한다.

이외에도 다양한 캐시전략이 있으며 데이터 종류, 크기, 액세스 패턴에 맞는 전략을 선택할 수 있다.

 

위와 같은 캐시 서버를 사용하기 위해서, 대부분의 캐시 서버들이 일반적으로 API를 제공하니 가져다 쓰기만 하면 된다.

 

캐시 사용 시 유의할 점

  • 캐시는 데이터 갱신이 자주 일어나지 않고, 참조가 빈번한 상황이라면 사용하는 것을 고려해 볼 만하다.
  • 캐시는 휘발성 메모리에 두기 때문에, 영속적으로 보관할 데이터는 캐시에 두어서는 안 된다.
  • 캐시에 보관된 데이터에 대해 만료 정책을 세우는 것이 좋다.
    너무 짧으면 캐시미스가 자주 일어나 데이터베이스를 너무 자주 읽게 될 것이며, 너무 길면 데이터베이스 원본과의 일관성이 보장되지 않는다.
  • 그렇다면 일관성은 어떻게 유지할까?
    저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 이 일관성은 깨질 수 있다.
    시스템이 확장될수록 캐시와 저장소 사이의 일관성을 유지하는 것은 어려운 문제가 된다.
  • 캐시 서버는 분산시키는 것이 좋다.
    한 대의 캐시 서버만 두는 경우 그 서버는 단일 장애 지점(SPOF: Single Point Of Faliure)이 될 가능성이 있다.
  • 캐시 메모리는 클수록 좋다.
    캐시 메모리가 너무 작으면 액세스 패턴에 따라서는 데이터가 너무 자주 캐시에서 버려진다.
    때문에 캐시 메모리를 과할당하여 캐시에 보관될 데이터가 갑자기 늘어났을 때의 상황을 대비할 수 있다.
  • 그럼, 캐시가 다 차서 데이터를 방출할 때, 방출 정책은 무엇인가?
    가장 널리 쓰이는 것은 LRU 알고리즘이다. 경우에 맞게 LFU, FIFO 등 다양한 정책을 적용할 수 있다.

 

CDN

캐시 서버를 두어 요청에 대한 데이터를 데이터베이스까지 접근하지 않고 빠르게 응답할 수 있게 되었다.

이제는 CDN을 통해 정적 콘텐츠를 캐시 할 것인데, CDN은 정적 콘텐츠를 전송하는데 쓰이는, 지리적으로 분산된 서버의 네트워크이다. 이미지, 비디오, CSS, JavaScript 파일 등을 캐시 하여 빠르게 가져올 수 있다.

 

CDN 동작 방식은 아래와 같다. 어떤 사용자가 웹사이트에 방문하면 가장 가까운 CDN서버가 정적 콘텐츠를 전달하게 된다.

  1. client A가 이미지 URL을 이용해서 image.png에 접근한다. URL의 도메인은 CDN 서비스 사업자가 제공한 것이다.
    e.g. https://mysite.cloudfront.net/image.png
  2. CDN 서버의 캐시에 해당 이미지가 없다면 서버는 origin 서버에 요청하여 파일을 가져온다.
    e.g. origin서버: 웹 서버 or S3등 정적 콘텐츠 저장소 등
  3. origin 서버가 파일을 CDN 서버에 반환한다. 응답의 HTTP 헤더에는 TTL 값을 두어 캐시 만료 기간을 둔다.
  4. CDN서버는 파일을 캐시하고 clientA에게 반환한다. 이미지는 캐시 만료 기간이 끝날 때까지 캐시 되어 존재한다.
  5. client B가 같은 이미지에 대한 요청을 CDN 서버에 전송한다.
  6. 만료되지 않은 이미지에 대한 요청은 CDN 서버의 캐시를 통해 처리한다.

CDN 사용 시 고려사항

  • 비용: CDN은 보통 제3 사업자에 의해 운영된다. 즉, CDN으로 요청하고 응답받는 과정에서 트래픽에 따른 요금을 내야 한다.
    자주 사용되지 않는 콘텐츠를 캐싱하는 것은 이득이 크지 않으므로 CDN에서 빼는 것이 좋다.
  • 적절한 만료 기한 설정: 시의성이 중요한 콘텐츠의 경우 만료 시점을 잘 정해야 한다. 짧으면 origin에 자주 요청하게 되고, 길면 콘텐츠의 신선도가 떨어진다.
  • CDN 장애 대처 방안: CDN 자체가 죽었을 때, 어떻게 서비스가 동작해야 할지 고려해야 한다.
    예를 들어, CDN 요청이 일시적으로 오지 않을 경우 문제를 감지하고, origin에 직접 요청하도록 클라이언트를 구성할 수 있다.
  • 콘텐츠 무효화 방법: 아직 만료되지 않은 콘텐츠라 하더라도 CDN에서 제거해야 할 경우가 있다. 이럴 땐 콘텐츠를 무효화시키는 방법이 있는데, 아래와 같다.
    • CDN 서비스 사업자가 제공하는 API를 이용하여 콘텐츠 무효화
    • 캐시 버저닝을 통해 새로운 버전이 존재함을 알려준다.

  1. CDN: 정적 콘텐츠는 더 이상 웹 서버를 통해 서비스되지 않으며, CDN을 통해 제공하여 더 나은 성능을 보장한다.
  2. Cache: 캐시를 사용함으로써 데이터베이스의 부하를 줄이고, 더 나은 성능을 보장한다.

 

무상태(Stateless) 웹 계층

앞서 웹 계층은 로드밸런서를 이용해서 웹 서버를 증설시키는데 부담이 없었다.

근데 사실 웹 서버를 자유롭게 수평적 확장을 하기 위해서는 웹 계층에서 상태 정보를 제거하는 것이 중요하다.
(여기서 상태란 사용자 세션데이터 등을 말한다.)

상태가 필요하다면 상태 정보를 별도의 저장소에 보관하고, 필요할 때 가져오도록 처리해야 한다.

그럼.. 왜 상태를 가지고 있으면 수평적 확장이 어려울까?

 

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

위 그림을 통해 상태 정보에 의존적인 수평적 확장이 왜 어려운 지 알아보자.

clientA의 세션 정보나 이미지 같은 상태 정보가 서버 1에 저장되었다.
그렇기 때문에 clientA가 인증하기 위해서 서버 2로 요청하면 실패, 서버 1로 요청하면 성공이다.

즉, 같은 client의 요청은 항상 같은 서버로 전송되어야 한다는 큰 문제가 발생한다.

물론, 로드밸런서가 이러한 세션 불일치 문제를 해결하기 위해서 sticky session(고정 세션)이라는 기능을 지원한다.

하지만, 로드밸런서에게 이러한 기능까지 위임하는 것이 부담을 주는 행위이고, 로드밸런서 뒷단에 서버를 추가하거나 제거하기도 까다로워진다.

 

Stateless(무상태) 아키텍처

위와 같은 구조로 변경하면 client가 HTTP요청을 보내면 어떤 웹 서버로 전달되어도 상관없다.

clientA가 인증 요청을 위해 서버 2로 요청을 보내게 될 경우, 서버 2는 상태 정보를 공유 저장소로부터 가져와 인증하게 된다.

이러한 구조는 상태 정보가 웹 서버로부터 물리적으로 분리되도록 해주고, 덕분에 단순하고 안정적이며 규모확장에 용이하다.

(물론, 인증상태를 유지하기 위한 "로그인"을 통해 인증상태를 유지할 때는 웹 서버가 웹 브라우저에 상태 정보를 전달해 줄 수 있다.

그리고, 브라우저에서 사용자에 대한 인증 상태를 유지할 수 있다. 그렇게 웹 브라우저에 저장하는 곳이 쿠키나 세션 등이 된다.)

 

 

세션 데이터를 웹 계층에서 분리하고 별도의 공유 저장소를 만들었다.

"이 공유 저장소는 관계형 DB일 수도 있고, Memcached/Redis 같은 캐시 시스템일 수도 있고, NoSQL일 수도 있다.
여기서는 NoSQL을 사용하였는데, 규모 확장이 편해서다."
(라고 책에 나와있는데 왜 NoSQL이 규모확장이 편한지에 대해 알아볼 필요가 있어 보인다.
나 같으면 키-값 구조의 세션 데이터이고, 빠른 read작업을 위해 Redis를 사용했을 것 같다.
나중에 비교를 통한 이해를 해봐야 할 것 같다.)

 

이렇게 무상태 웹 계층을 가짐으로써 트래픽 양에 따라 웹 서버를 자동으로 추가하거나 삭제하는 오토스케일링이 가능해졌다. 
상태 정보가 웹 서버들에서 제거되었으므로 자동으로 규모를 확장할 수 있게 되었다.

 

데이터 센터

지리적으로 멀리 떨어진 곳에서도 쾌적하게 서비스에 접근하기 위해서는 여러 데이터 센터를 지원하는 것이 필수다.

장애가 없는 상황에서 지리적 라우팅을 통해서 가장 가까운 데이터 센터로 접근하게 된다.

이 원리에 대해 간단하게 설명하면 지리적 라우팅에서의 geoDNS는 사용자의 위치에 따라 도메인명을 어떤 IP주소로 변환할지 결정해 주는 DNS 서비스이다.

데이터 센터를 적용한 모습이다.

여기서, 서울 데이터 센터에 심각한 장애가 발생하면 모든 트래픽이 미국 데이터 센터로 전송된다.
당연히 한국에서 접속하는 사용자는 보다 느린 서비스를 제공받을 것이다.

하지만, 접속은 가능하므로 데이터센터 지원을 통해 가용성을 높였다고 볼 수 있다.

 

데이터센터 아키텍처에서 해결해야 할 사항들

  1. 트래픽 우회: geoDNS와 같이 사용자에게서 가장 가까운 데이터센터로 트래픽을 보내주는 정책도 있지만, 그 외에 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야 한다.
  2. 데이터 동기화: 위 그림에서 볼 수 있듯이 데이터 센터마다 별도의 데이터베이스를 사용하고 있는 상황일 수 있다.
    한 DC에서 장애가 발생하여, failover(장애 자동 복구 기능)를 통해 다른 데이터센터의 데이터베이스로 우회된다 해도 원하는 데이터가 없을 수 있다. 이런 상황을 막기 위한 일반적인 전략은 데이터를 여러 데이터센터에 걸쳐 다중화 하는 것이다.(데이터센터 다중화)
    (넷플릭스가 여러 데이터센터에 걸쳐 데이터를 다중화한 방식이라고 한다.
    https://netflixtechblog.com/active-active-for-multi-regional-resiliency-c47719f6685b)
  3. 테스트와 배포: 여러 데이터센터에 걸쳐 시스템이 구성되었다면 당연히 여러 위치에서 테스트해보는 것이 중요하다.
    자동화된 배포 도구를 사용할 수 있다.

 

메시지 큐

메시지 큐는 메시지의 무손실을 보장하면서 메시지의 버퍼 역할을 하고, 비동기적으로 메시지를 전송하는 방법이다.

메시지 큐의 기본 아키텍처는 아래와 같다.

 

 

  1. 생산자 또는 발행자라고 불리는 입력 서비스가 메시지를 만들어 메시지 큐에 발행한다.
  2. 큐에는 보통 소비자 혹은 구독자라고 불리는 서비스 혹은 서버가 연결되어 있는데,
    메시지를 받아 그에 맞는 동작을 수행하는 역할이다.

메시지 큐의 장점

  • 메시지 큐를 이용하면 소비자 서비스와 생산자 서비스의 결합도가 느슨해진다.
    그러므로, 소비자와 생산자 각각을 원하는대로 규모확장이 가능하다.
  • 결합도가 낮으므로, 생산자는 소비자 프로세스가 다운되어도 메시지를 발행할 수 있고
    소비자는 생산자 서비스가 가용상태가 아니더라도 메시지를 수신받을 수 있는 독립적으로 행동이 가능해진다.
  • 무손실을 보장한다.
    메시지 큐에 일단 보관된 메시지는 소비자가 꺼낼 때까지 안전히 보관되는 특성을 지닌다.

메시지 큐 예시

사진 보정 애플리케이션이 있을 때,

보정 작업 자체가 시간이 오래 걸릴 수 있는 프로세스 이므로 비동기적으로 처리하면 편하다.

웹 서버는 사진보정작업을 메시지 큐에 넣고,
사진보정작업 프로세스들은 이 작업을 메시지 큐에서 꺼내어 비동기적으로 처리한다.
이렇게 하면 생산자와 소비자 각 서비스의 규모는 독립적으로 확장될 수 있다.

예를 들어, 큐의 크기가 커지면 사진보정작업 프로세스를 추가해야 처리 시간을 단축시킬 수 있으며
큐가 항상 거의 빈 상태라면 작업 프로세스이 수를 줄일 수 있다.

 

데이터베이스의 규모 확장

저장할 데이터가 많아질수록 데이터베이스에 대한 부하도 증가한다.

그때가 오면 데이터베이스를 증설해야 하는데, 데이터베이스 규모 확장 방법에는 두 가지가 있다.

수직적 규모 확장(Scale-up), 수평적 규모 확장(Scale-out)


여기서 하나 헷갈렸던 점이 있는데, 데이터베이스의 규모 확장 방법에는 scale-up과 scale-out(샤딩)이 있는 것이고,
데이터베이스를 분할하는 방식에는 수직적 파티셔닝과 수평적 파티셔닝(샤딩)이 존재한다.


 

수직적 규모 확장(Scale-up)

기존 데이터베이스 서버에 고성능 자원을 증설하는 방식이다.
예를 들어 스택오버플로우의 2013년 한 해 방문한 천만명의 사용자 전부를 단 한 대의 마스터 데이터베이스로 처리하였다고 한다.

하지만, 수직적 접근법에는 아래와 같은 문제가 있다.

  • 무한 증설 불가(하드웨어를 추가하는 개념이기 때문에 한계가 존재)
  • SPOF(Single Point Of Failure) 발생 가능
  • 고성능 서버로 갈수록 가격이 올라가기 마련이다.

수평적 규모 확장(Scale-out)

샤딩이라고도 부른다. 그리고, 샤딩은 수평적 파티셔닝의 일종이기도 한다.

(참고. 수직적 파티셔닝: 속성별로 테이블을 나누어 성능을 향상시키는 방법 -> 정규화는 아니다.)

샤딩은 대규모 데이터베이스를 샤드라고 부르는 작은 단위로 분할하는 기술이다.
모든 샤드는 같은 스키마를 쓰지만 샤드에 보관되는 데이터 사이에 중복은 없다.

(맨 처음 샤딩에 대해 들었을 당시에는 DB 다중화(Replication)과 헷갈려서 일관성을 어떻게 유지하는지에 대해 막 찾아봤던 기억이 있다...ㅎㅎ)

 

이렇게 샤딩 전략을 구현할 때 고려해야 할 가장 중요한 점은 샤딩 키를 어떻게 정하느냐이다. 샤딩키는 파티션 키라고도 부른다.

이 샤딩 키는 데이터가 어떻게 분산될 지 정하는 하나 이상의 칼럼을 구성된다. 예를 들어 사용자의 Id가 될 수도 있고, UUID가 될 수도 있을 것이다. (이렇게 분산 시스템에서 유일 ID를 설계하는 방법에 대해서도 알아볼 예정이다.)

 

샤딩 전략을 도입할 때, 풀어야 할 문제

  • 데이터의 재샤딩(resharding): 데이터가 너무 많아져서 샤딩을 다시 해야하거나, 특정 샤드에만 데이터가 몰려 데이터 분포가 균등하지 못할 때
    재 샤딩을 해야한다. 이런 재 샤딩의 경우 샤드 키를 계산하는 함수를 변경하고 데이터를 재 배치해야 하는데 안정해시 기법을 통해 이 문제를 해결할 수 있다.
  • celebrity 문제: 핫스팟 키 문제라고도 무른다. 특정 샤드에 질의가 집중되어서 서버에 과부하가 걸리는 문제이다.
    이유는 특정 샤드에 질의가 많이 일어나는 데이터들에 의해 발생하는 것인데, 그렇기 때문에 해결하기 위해 문제가 되는 데이터들을 각 샤드에 하나씩 할당하거나, 심지어는 더 잘게 쪼개야 한다.
  • 조인과 비정규화: 여러 샤드 서버로 하나의 데이터베이스를 쪼개고 나면 여러 샤드에 걸친 조인연산이 힘들어진다.
    이를 해결하기 위해 데이터베이스를 비정규화하여 하나의 테이블에서 질의가 수행될 수 있도록 해야 한다.

 

단일서버 -> 로드밸런서, DB 다중화,  캐시, CDN, HTTP 세션 저장소, 메시지 큐, DB 샤딩을 적용한 최종 아키텍처