Post

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

https://contents.kyobobook.co.kr/sih/fit-in/458x0/pdt/9788966263158.jpg

응답시간 줄이기

캐시

캐시란, 값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 뒤 이은 요청이 보다 빨리 처리될 수 있도록 하는 저장소이다.

앱의 성능은 통상 DB를 얼마나 자주 호출하느냐에 크기 좌우되는데, 캐시를 사용하면 그런 문제를 크게 완화할 수 있다.(아래 동영상을 보면 캐싱 모듈 적용 전후로 21ms 에서 3ms 로 응답 시간이 줄어드는 걸 볼 수 있다.)

캐시 사용 시 유의 해야 할 점

  1. 데이터 갱신은 자주 일어나지 않지만 참조는 빈번하게 일어난다면 캐시를 사용해볼만 하다.
  2. 캐시는 캐시서버가 재시작되면 모든 데이터가 사라지기 때문에 중요한 정보는 여전히 지속적 저장소에 두어야한다.
  3. 캐시 데이터의 만료 정책을 마련해 두어야한다. 만료 기간이 너무 짧으면 db를 너무 자주 읽게 되어서 곤란하고, 길면 원본 db와 차이가 날 가능성이 높아진다.
  4. 일관성 유지에 신경을 써야한다. 일관성(consistency)란 DB 내 원본 데이터와 캐시 내 사본이 동일한지 여부다. 여러 지역에 걸쳐 시스템이 확장된다면 단일 트랜잭션으로 DB와 캐시를 갱신하는게 어려워진다. 필요 시 아래 논문을 참고 해보자. Scaling Memcache at Facebook
  5. 캐시 서버가 앱의 단일 장애 지점이 되는 것을 피하기 위해 여러 지역에 걸쳐 캐시 서버를 분산 시켜야 한다.
  6. 캐시 메모리의 크기를 적절히 정해야 한다. 메모리 크기가 너무 작으면 데이터가 너무 자주 밀려나 버려 성능이 떨어질 수 있다. 이를 막으려면 캐시 메모리를 과할당(overprovision)하는 것도 좋은 방법이다. 이 방법을 쓰면 갑자기 캐싱할 데이터가 늘어도 안심이다.
  7. 캐시 데이터 방출 정책을 경우에 맞게 적용하자. LRU, LFU, FIFO 등이 있다. 참고 - 페이지 교체 알고리즘

CDN (Content Delivery Network)

CDN 이란?

CDN은 정적 콘텐츠를 전달할 때 쓰이는, 지리적으로 분산된 서버의 네트워크 기술입니다.

이미지, 비디오, CSS, JavaScript 등 정적 파일을 캐시할 수 있습니다.

사용자가 웹사이트에 방문하면 가장 가까운 CDN 서버가 정적 콘텐츠를 전달해줍니다.

CDN 의 작동 방식

  1. 예를 들어 사용자 댕댕이(🐶)가 이미지 url 을 이용해 image.png 에 접근합니다. 이미지 url 은 보통 cdn 서비스 사업자(cloudfront, kamai)가 제공합니다. (https://mysite.cloudfront.net/image.png)
  2. 먼저 가까운 CDN 서버를 먼저 뒤져 봅니다.
  3. CDN 서버에 이미지가 없는 경우 원본 서버에 파일을 요청합니다.
  4. 원본서버가 파일을 CDN 서버에 응답하면서 얼마나 오랫동안 캐싱해도 되는지 TTL을 적어줍니다.
  5. CDN 서버는 파일을 캐시하면서 댕댕이(🐶)에게 파일을 반환합니다.
  6. 다른 사용자 야옹이(😸)가 해당 이미지를 CDN 서버에 요청합니다.
  7. 만료되지 않은 이미지 파일이라면 야옹이(😸)에게 캐싱 되어있는 파일을 보냅니다.

CDN 사용 시 주의할 점

  1. 비용 보통 제 3 사업자가 운영하는 CDN을 사용하게 되며 데이터 전송량에 따라 비용을 지불합니다. 따라서 자주 사용되지 않는 콘텐츠는 CDN에서 빼는 것이 좋습니다.
  2. 적절한 만료 시한 설정 시의성이 중요한 콘텐츠의 너무 ttl 이 길면 신선도가 떨어질 수 있습니다. 너무 짧으면 원본 서버에 빈번하게 접속하게 되어 성능 면에서 무용지물이 됩니다.
  3. CDN 장애 시 대처 방안 CDN 서버가 고장 났을 경우 대비책을 세워둬야 합니다. 가령 해당 문제를 감지하여 일시적으로 원본 서버에서 콘텐츠를 가져오게끔 모니터링한다든지 하는 구성이 필요합니다.
  4. 콘텐츠 무효화 방법 필요 시 콘텐츠 만료기한이 되기 전에 CDN 에서 제거해야 하는 경우를 대비해야 합니다.
    • CDN 사업자가 제공하는 delete api 를 사용하는 방법
    • 콘텐츠를 오브젝트 버저닝하는 방법 (image.png?v=2)

CDN 사용으로 개선된 점

  1. 정적 콘첸츠를 웹서버에서 제공하지 않기 때문에 더 나은 성능을 보장한다.
  2. 캐시를 사용하여 DB 서버의 부하를 줄여준다.

규모 확장성 키우기

무상태 웹 계층

상태정보를 웹 계층을 제거하고 외부 데이터 베이스에서 처리하게 하여 수평적으로 확장하는 방식이다.

상태정보 : 사용자의 세션 데이터 처럼 웹서버의 인메모리에 저장하는 정보

우리는 웹서버를 주서버와 부서버로 나누어 서비스하고 있다. 상태정보에 의존적인 설계의 경우, 웹서버마다 클라이언트 정보를 따로 저장해야한다. 대부분의 로드밸런서가 이 문제를 위해 고정 세션등의 기능을 제공하고 있지만 해당 문제를 해결하기 위해 자원을 부담하고 소모해야 한다.

이런 문제를 해결하기 위해 무상태 아키텍처가 탄생했다.

상태정보를 웹서버로 부터 물리적으로 분리해서 공유 저장소에서 데이터를 저장하고 가져온다. (Memcached, redis 같은 캐시 시스템이나 NOSQL 사용 가능)

이렇게 상태정보를 분리함으로써 우리는 auto-scailing 으로 자유롭게 트래픽에 따라 서버를 늘렸다 줄였다 할 수 있게 됐다. 규모 확장성이 좋아졌다.

메시지 큐

메시지 큐는 메시지의 무손실(durability)를 보장하는, 비동기 통신을 지원하는 컴포넌트이다.

메시지의 버퍼 역할을 하며 비동기적으로 전송한다.

메시지 큐를 이용하면 서비스 간 결합이 느슨해지기 때문에 규모 확장성이 보장된다.

예를 들어 사진 보정 앱을 만든다고 해보자.

사진 보정은 시간이 오래 걸릴 수 있는 작업이기 때문에 비동기적으로 처리하면 편리하다.

웹서버(생산자)는 사진 보정작업을 큐에 넣어둔다.

그러면 사진 보정 프로세스(소비자)들은 자기 일이 완료될 때마다 메시지 큐에서 작업을 꺼내가서 비동기적으로 완료한다.

이렇게 하면 생산자와 소비자 서비스가 서로 분리되어 있으니 각기 독립적으로 확장할 수 있다.

규모의 탄력적 조절(규모 확장성)

큐의 크기가 커지면(사진 보정 작업이 너무 많아 쌓이고 있으면) 유동적으로 더 많은 작업 프로세스(소비자)를 추가하여 처리 시간을 줄일 수 있다.

큐가 거의 항상 비어 있는 상태라면 작업 프로세스(소비자)의 수를 줄일 수 있을 것이다.

데이터베이스의 규모 확장

저장할 데이터가 많아지면 DB에 대한 부하도 증가한다. 그 때가 오면 DB를 증설한 방법을 찾아야 한다.

수직적 확장(Scale up)

스택오버플로처럼 앗싸리 더 크고 고성능인 DB를 써버린다. 1년간 천만명의 사용자 전부를 마스터 DB 1 대로 처리했다고 한다. AWS RDS 는 24TB RAM 서버도 팔고 있다.

다만 이렇게 수직적으로 접근하면 주의해야할 점이 있다.

  1. DB 서버 하드웨어에는 한계가 있어서 무한 증설하기엔 불가능에 가깝다.
  2. SPOF(Single Point of Failure)로 인한 위험성이 크다. DB 가 고장나는 게 단일장애지점이 되어서 전체 시스템 동작이 중단되어 버릴 수도 있다.
  3. 비용이 많이 든다. 몰라도 엄청 비쌀거다.

수평적 확장(Scale Out)

DB의 수평적 확장은 샤딩(Sharding)이라고 부른다.

대규모 DB를 Shard 라고 부르는 작은 단위로 분할하는 기술을 샤딩이라고 부른다.

예를 들어 user_id % 4 를 해시함수로 사용해서 저장될 DB를 정한다.

user_id 처럼 데이터가 어떻게 분산될 지 정하는 하나 이상의 칼럼을 sharding key, partition key라고 부른다.

샤딩 키를 통해 db에 질의를 보낼 때도 효율적으로 보낼 수 있다.

샤딩 시 고려해야 할 점

  1. 데이터의 재샤딩 특정 db 하나만 데이터가 너무 많아져서 샤드간 데이터 분포가 균등해지지 못할 때가 있다. 이런 경우를 샤드 소진이라고 하는데 이런 경우 샤드 키를 계산하는 함수를 변경하고 데이터를 재배치해야 한다. 안정 해시 기법을 이용해 해결할 수 있다.
  2. 유명인사(Celebrity) 문제 유명인사 키를 핫스팟키라고도 부르는데, 특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 걸 말한다. 우연히 SNS DB에 블랙핑크 제니, 비욘세, 뉴진스, 레이디 가가가 같은 샤드에 저장되어 버릴 수도 있다. 그럼 그 사람들의 인스타를 보러오는 팬들이 많아서 해당 샤드는 read 연산 때문에 과부하가 걸리게 될거다. 이 문제를 풀려면 위에 나열한 유명인사들에게 각각 샤드 하나를 부여해야할 수도 있다.
  3. 조인과 비정규화 하나의 db를 여러 샤드로 쪼개고 나면, 각각의 샤드에 있는 데이터들끼리 join 하기가 힘들어 진다. 이를 해결하는 한 가지 방법은 DB를 비정규화 하여 테이블에서 질의가 수행되게 하는 것이다. 아니면 굳이 관계형 db가 요구되지 않는 기능은 NoSQL로 이전해버리는 방법도 있다.

가용성 키우기

데이터 센터

전세계 어디서든 쾌적하고 빠르게 사용하려면 지리적으로 여러 장소에 데이터 센터를 두면 된다.

사용자의 요청이 가장 가까운 데이터 센터로 안내되는 절차를 지리적 라우팅(geoDNS-routing)이라고 부른다.

데이터 센터 중 하나에 심각한 장애가 발생하면 모든 트래픽은 장애가 없는 데이터 센터로 전송할 수 있다.

데이터 센터 주의할 점

  • 트래픽 우회 : 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야 한다. (예- GeoDNS)
  • 데이터 동기화 : 데이터 센터마다 별도의 데이터베이스를 사용하고 있다면 장애가 발생했을때 자동으로 이웃 DB로 트래픽이 이동한다고 해도 찾는 정보가 거기 없을 수도 있다. 해결 방안은 보편적으로 여러 데이터 센터에 데이터를 다중화하는 방법을 사용한다. (넷플릭스 테크블로그 : https://netflixtechblog.com/active-active-for-multi-regional-resiliency-c47719f6685b)
  • 테스트와 배포 : 여러 데이터 센터를 쓰고 있다면 웹사이트를 업데이트할 때마다 여러 위치에서 테스트해보는 것이 중요하다. 또한 자동화된 배포 도구로 모든 데이터센터에 동일한 서비스가 설치될 수 있게 해야한다.

결론 : 백만 사용자(C10K)가 와도 거뜬한 시스템 만들기의 시작

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

지금까지 나눈 방식들로 해결되지 않을 만큼 서비스가 성공하고 사용자가 많아졌다면 이제 시스템을 더 최적화 하고 더 작은 단위의 서비스로 분할 설계 하는 법을 같이 알아보자.

https://webhostinggeeks.com/blog/c10k-problem-understanding-and-overcoming-the-10000-concurrent-connections-challenge/

This post is licensed under CC BY 4.0 by the author.