[에디터 🐧] 구독자 님 안녕하세요, 오늘 주간SaaS 는 미국 소프트웨어 기업 중 역대 최대 기업공개(IPO) 규모를 자랑하며 뉴욕증권거래소 상장한 이제는 누구다 다 아는 기업 Snowflake 아키텍처를 소개 하려고 합니다.
작은 규모의 기업 부터 대형 기업 까지 멀티 테넌트 아키텍처 구조로 데이터 분석 서비스를 제공하는 Snowflake의 멀티 테넌트 아키텍처는 어떤 모양일지 궁금했는데, 그 힌트를 찾을 수 있는 Snowflake의 Control Plane 구조를 소개한 블로그가 있어 주요 부분을 한글로 의역 및 요약 했습니다.
블로그는 실제로 2022년 Snowflake가 발표한 “Elastic cloud services: scaling snowflake's control plane” 이라는 논문을 요약 하고 있습니다.
내용이 다소 길고 어렵지만 B2B SaaS 서비스들이 고민하는
- 서비스 배포와 롤백
- Zone 별, Region 별 고가용성 유지
- 비용 효율적인 인스턴스 사용
- Noisy Neighbor 문제 해결 (Throttling, Auto Scaling)
등에 관한 좋은 참고 내용과 인사이트가 담겨 있습니다. 블로그에는 다 담기지 못한 너무 좋은 인사이트들이 논문에 담겨 있습니다. 논문 역시 꼭! 읽어보시기를 추천 합니다.
Elastic Cloud Services: Scaling Snowflake’s Control Plane
Snowflake는 전 세계에 분산된 데이터 웨어하우스를 만드는 회사입니다. Snowflake는 부하에 빠른 확장성을 가지면서도, 여러 클라우드와 리전을 통해 단일 장애 지점을 줄여 고객의 business-critical 한 query 들에 응답하고 있습니다.
이번 시간에는 Snowflake의 워크로드 오케스트레이션을 담당하는 핵심 구성 요소인 Elastic Cloud Services(ECS)의 설계와 구현에 대해 설명하려고 합니다.
설명에 앞서, Snowflake의 3개의 주요 레이어들을 살펴보겠습니다. Snowflake는 서비스들이 모여있는 Cloud Services 계층과 고객의 데이터에 대한 query 실행을 담당하는 Query Processing 계층, 데이터를 관리하고, 데이터베이스 레코드를 보유하고 있는 Object Storage 계층으로 이루어져 있습니다.
각 Snowflake 고객은 하나 이상의 Snowflake 웨어하우스를 구성할 수 있으며, 다른 사용자 간에 격리를 제공합니다. 고객이 웨어하우스를 구성하면 해당 웨어하우스에 버전이 할당되는데, 이 버전은 고객의 쿼리가 어디서 실행되는 지를 결정합니다. 이 때 중요한 점은 이렇게 구성한다고 해서, Computing resource 를 새로 구성하는 것이 아니라는 것입니다. Snowflake 는 고객이 query를 보낼때 동적으로 리소스를 확장합니다.
어떻게 이렇게 작동할 수 있을까요? Snowflake 는 ECS 를 이용해서 다음의 세가지를 구현하고 있습니다.
- 자동 코드 관리 : 제품을 구동하는 코드는 지속적으로 업그레이드되며, ECS는 이러한 업그레이드를 자동으로 안정적으로 처리하도록 설계되었습니다.
- 가용 영역 간 부하 분산: ECS는 단일 장애 지점을 줄이기 위해 여러 클라우드에 걸쳐 부하를 조정합니다.
- 스로틀링 및 자동 확장: 고객의 요청 수가 급격히 증가할 수 있으며 ECS는 이러한 쿼리를 처리할 수 있어야 합니다
자동 코드 관리
롤아웃
Snowflake의 제품을 구동하는 코드는 지속적으로 업데이트됩니다. ECS는 고객에게 부정적인 영향을 미칠 가능성을 줄이기 위해 점진적으로 변경 사항을 롤아웃하도록 설계되었습니다. 이 프로세스는 완전히 자동화되어 있기 때문에, 휴먼 에러를 최소화하고 새 코드를 빠르고 안정적으로 롤아웃할 수 있습니다. 또한 VM이 종료되기 전에 쿼리 실행을 완료할 수 있도록 하는 등 고객 쿼리가 중단되지 않도록 보장하는 조치도 포함되어 있습니다.
클라우드 서비스 클러스터에 업데이트를 롤아웃하기 위해 ECS는 먼저 업데이트된 소프트웨어 버전으로 새 가상 머신(VM)을 준비합니다. 그런 다음 ECS는 캐시를 워밍업(이 백서에서는 캐시를 워밍업하는 방법에 대한 구체적인 내용은 제공하지 않지만, 현재 실행 중인 고객 쿼리가 새 머신으로 전달되는 '다크 롤아웃'을 통해 이루어질 가능성이 높습니다.)하여 머신을 준비하고 사용자 쿼리를 새 VM으로 전달하기 시작합니다.
진행 중인 쿼리에 대한 중단을 최소화하기 위해 이전 버전을 사용하는 VM은 워크로드가 완료될 때까지 계속 작동합니다. 새 버전과 이전 버전의 소프트웨어를 동시에 사용하는 VM을 실행하면 리소스 측면에서 비용이 더 많이 들지만 고객에게 영향이 발생할 경우 신속하게 롤백할 수 있습니다.
Pool
규모가 커짐에 따라, 머신은 다양한 이유로 고장 나거나 최적의 성능을 발휘하지 못합니다. 이 문제를 해결하기 위해 ECS는 컴퓨팅 노드의 기반이 되는 메모리, CPU 등과 같은 클라우드 리소스를 적극적으로 관리하여 상태를 추적합니다. 이 모니터링을 기반으로 ECS는 VM의 수명 주기의 5가지 단계 중 하나에 해당하는 리소스를 포함하는 클러스터 풀 간에 VM을 이동합니다
- 사용 가능(Free) Pool: 사용할 준비가 된 VM을 포함합니다.
- 격리된(Quarantine) Pool: 아직 완료 보류 중인 작업을 해결하기 위해 클러스터에서 제거해야 하는 VM을 포함합니다.
- 활성화(Active) Pool: 클러스터의 일부이며 고객 워크로드를 적극적으로 처리하는 정상 VM을 포함합니다.
- 묘지(Graveyard) Pool: 종료할 준비가 된 VM을 포함합니다.
- 홀딩(Holding) Pool: 디버깅 목적을 가지고 활성 서비스에서 VM을 제거하고, 종료하지는 않은 상태입니다.
풀 사용에는 두 가지 예시가 있습니다.
첫 번째는 클러스터가 업그레이드될 때 이전 버전의 소프트웨어를 실행하는 VM이 활성화 풀에서 격리되고, 마지막으로 Graveyard 풀로 이동할 때 발생하는 일련의 상태 전환입니다.
두 번째 고객 쿼리 처리와 관련하여 에러가 발생했을 때, 사용 가능 풀에서 격리 풀로 이동하는 예를 다룹니다.
가용 영역 간 밸런싱
ECS 는 클라우드 Region 내에서 장애가 발생할 경우에 고객에게 미치는 영향을 최소화하기 위해 가용 영역 간에 로드 밸런싱을 수행합니다. VM(가상 머신)을 여러 가용 영역에 고르게 분산시킴으로써 한 영역에 장애가 발생하거나 다른 이유로 인해 사용할 수 없게 되는 경우 요청을 다른 영역에 있는 VM으로 리다이렉션할 수 있습니다. 이러한 접근 방식은 예기치 않은 중단이 발생하더라도 서비스의 가용성과 고객 대응력을 유지하는 데 도움이 됩니다. 가용성 영역 간 부하 분산은 서비스의 복원력과 안정성을 개선하는 데 도움이 되므로 클라우드 컴퓨팅에서 일반적으로 사용됩니다.
ECS는 클러스터 수준 밸런싱(고객 클러스터의 VM을 여러 영역에 분산하는 것을 목표로 함)과 글로벌 수준 밸런싱(전체 VM을 영역 간에 균등하게 분산하는 것을 목표로 함)을 구현하고 있습니다. 아래 그림을 보면 이해가 되실겁니다.
왼쪽의 Zone A 부터 Zone C 까지를 보면, Zone A 와 Zone B에는 고르게 분산되어 있지만, Zone C에는 분산되어 있지 않아서 글로벌 수준으로 봤을때에는 밸런싱되어 있지 않습니다.
가운데 그림을 보면, 초록색 워크로드는 Zone A 에만 존재해서 클러스터 수준에서 밸런싱을 맞추지 못하고 있습니다.
반면 오른쪽 그림은 글로벌 수준에서도, 클러스터 수준에서도 밸런싱을 맞추고 있습니다.
그렇다면, 로드 밸런싱은 어떻게 작동할까요? 클러스터를 확장할 때 ECS는 해당 클러스터에 대해 가장 부하가 적은 영역 집합 중에서 전 세계적으로 가장 부하가 적은 영역을 선택합니다. 클러스터를 축소할 때는 해당 클러스터에 대해 가장 부하가 많은 영역 집합 중에서 전 세계적으로 가장 부하가 많은 영역을 선택합니다.
이 두 가지 전략을 통한 확장이 작동하지 않거나 서로 충돌하는 경우도 있습니다. 예를 들어 왼쪽 그림처럼, 특정 영역의 클러스터에 할당할 VM이 없는 경우 클러스터 수준 밸런싱을 실행하지 못할 수 있습니다. 오른쪽 그림처럼, 클러스터 레벨에서의 밸런싱이 글로벌의 밸런싱을 나쁘게 만드는 경우도 있습니다.
Throttling 및 자동 스케일링
ECS는 예측할 수 없는 사용자 트래픽을 처리하기 위해 두 가지 접근 방식을 사용합니다
- Throttling: 고객 쿼리는 격리되어서 실행되어야 하고 (잘 격리되지 않으면 Noisy Neighbor 문제가 발생합니다.), 과도한 리소스를 소비해서는 안 됩니다.
- 자동 확장: 고객이 Snowflake의 데이터베이스로 전송하는 부하는 시간에 따라 달라지며, 기본 인프라는 이에 대응하여 자동으로 확장해야 합니다.
이 두가지의 접근 방식을 고려해 설계 할 때 다음 다섯 가지 원칙들에 대해 균형을 잡으려고 노력 합니다.
- 응답성: 쿼리가 사용자가 느끼는 지연 없이 실행되어야 합니다.
- 비용 효율성: 불필요한 리소스를 보유해서는 안 됩니다.
- 클러스터 변동성: 클러스터 구성의 잦은 변경은 성능과 비용에 영향을 미치므로 클러스터 구성의 불필요한 변경을 최소화해야 합니다.
- 처리량: 시스템은 수요에 맞게 확장할 수 있어야 합니다.
- 지연 시간: 쿼리가 적시에 완료되어야 합니다.
Throttling을 구현하기 위해 Snowflake는 고객 쿼리에 대한 VM 사용량을 기반으로 스케일링 결정을 내리는 동적 Throttling 접근 방식을 사용합니다. 동적 Throttling은 각 워크로드의 특정 수요를 고려하지 않는 정적 동시성 제한을 사용하는 대신 CPU 및 메모리 사용량을 기반으로 제한을 계산합니다. VM이 쿼리를 실행하다가 이러한 제한에 도달하면 상태 메트릭이 정상으로 돌아올 때까지 새 쿼리를 수락하지 않습니다. 이 접근 방식은 고객에게 일관된 서비스 경험을 보장하는 데 도움이 됩니다.
오토스케일링은 동적 Throttling이 사용하는 것과 유사한 시그널을 사용합니다. 클러스터 자동 확장 알고리즘은 VM 이탈과 같은 요인도 고려하며, 확장 및 축소를 최소화하는 것을 목표로 합니다. 이 알고리즘은 수평적(VM 추가) 및 수직적(크기 증가) 확장이 모두 가능합니다.
댓글
의견을 남겨주세요