Computer >> 컴퓨터 >  >> 프로그래밍 >> 데이터베이스

Amazon Aurora 고가용성(HA) 전략 완벽 가이드

이 글을 읽고 계시다면 Amazon Aurora에 대해 이미 들어보셨을 가능성이 높습니다. Amazon Aurora는 AWS가 RDS 서비스 제품군의 일부로 제공하는 PaaS 서비스로, MySQL과 PostgreSQL 두 가지 버전의 완전 관리형 관계형 데이터베이스 관리 시스템(RDBMS)을 제공하며, 두 엔진 모두와 와이어 호환성을 유지합니다. 그렇다면 이러한 특성은 고가용성(High Availability) 전략과 선택지에 어떤 영향을 미칠까요?

Amazon Aurora가 Amazon RDS의 MySQL 또는 PostgreSQL과 어떻게 다른지 궁금하실 수 있습니다. RDS 역시 완전 관리형 RDBMS 서비스이기 때문입니다. 맞습니다. 하지만 RDS는 사실상 표준 오픈소스 구현체를 EC2 인스턴스 플릿에서 실행하고 AWS가 관리하는 방식입니다. 반면 Aurora의 핵심적인 차이점은 AWS가 스토리지 엔진을 데이터베이스 엔진으로부터 분리했다는 점입니다. 즉, AWS가 오픈소스 데이터베이스에 '관심사 분리(Separation of Concerns)' 원칙을 적용한 것입니다.

관심사 분리(Separation of Concerns)

일반적으로 RDBMS는 범용 하드웨어 환경에서 실행되어야 합니다. 따라서 구현체는 OS와 하드웨어가 부과하는 제약 조건 안에서 DML·DDL 처리, ACID 준수 트랜잭션, 복제, 고가용성(HA), 장애 허용성 같은 현대적인 데이터베이스의 필수 기능들을 모두 충족해야 합니다. 하지만 만약 범용 하드웨어가 아닌 데이터베이스 전용으로 설계된 환경에서만 실행된다면 어떻게 될까요? 각 책임을 계층별로 분리하여 데이터베이스 엔진과 스토리지 엔진이 각자의 역할에 집중하고 특화될 수 있습니다.

그 결과, 고가용성과 성능이 크게 향상됩니다. 실제로 Aurora는 표준 MySQL 대비 최대 5배, 표준 PostgreSQL 대비 최대 3배의 성능을 제공합니다.

속도가 빨라졌다는 것은 알겠는데, 과연 특화된 데이터베이스 엔진과 스토리지 엔진이 HA에는 어떤 도움을 줄까요? 여러 방면에서 도움이 되지만, 그 전에 Aurora 스토리지 엔진의 작동 방식을 간단히 살펴보면 이러한 분리 구조가 어떻게 HA로 이어지는지 이해하는 데 도움이 됩니다.

데이터가 Aurora 스토리지 엔진에 기록될 때, 엔진이 데이터의 일관성, 정확성, 내구성을 보장합니다. 데이터는 3개의 가용 영역(AZ)마다 2개 위치씩, 총 6곳에 기록되며, 이 모든 과정이 올바르게 수행되도록 하는 복잡성은 스토리지 엔진이 처리합니다. 다소 단순화된 설명이지만, 본질적으로 데이터베이스 엔진은 이제 '쓰고 잊기(fire-and-forget)' 방식으로 동작할 수 있습니다. 데이터가 제대로 기록되었는지, 트랜잭션 로그 관리, 장애 발생 시 복구 가능성 등을 더 이상 걱정할 필요가 없습니다.

이처럼 데이터베이스 엔진에서 스토리지 관련 부담을 제거함으로써 다양한 HA 전략을 활용할 수 있게 됩니다.

읽기 전용 복제본(Read Replica)

읽기 전용 복제본 개념 자체는 Aurora 이전부터 존재했지만, 오픈소스 솔루션에서는 로그 배송(log shipping)이나 쿼리 재실행(query replay) 방식으로 구현됩니다. 반면 Aurora의 Read Replica는 마스터와 정확히 동일한 스토리지에 읽기 전용으로 접근합니다. 덕분에 데이터가 기록된 시점부터 Read Replica에서 조회 가능해지는 시점까지의 지연이 극히 적습니다(이런 상황에서는 '복제 지연(replication lag)'이라는 표현조차 어울리지 않습니다). 여러 개의 Read Replica가 필요한 경우에도 모든 복제본이 동일한 데이터를 바라보므로, 표준 MySQL·PostgreSQL 구현에서 발생하는 마스터의 오버헤드와 복잡성이 사라집니다. 이러한 특징들이 결합되어 마스터에 장애가 발생하면 Read Replica가 즉시 인계받을 수 있습니다. 또한 AWS가 프로비저닝된 용량을 충족하도록 장애 인스턴스를 새 인스턴스로 교체하고, DNS를 새 마스터로 갱신까지 해줍니다.

읽기 비중이 높은 애플리케이션에는 훌륭한 솔루션입니다. 다만 유의할 점이 있습니다. 첫째, 기본(Primary) 인스턴스는 전체 쓰기 부하를 감당할 수 있을 만큼 충분히 커야 합니다. 둘째, 쓰기 HA를 위해서는 마스터와 동일한 크기의 Read Replica를 최소 하나 이상 프로비저닝하고, 해당 복제본을 장애 시 승격 우선순위 인스턴스로 설정하는 것이 좋습니다. 이렇게 하면 장애 상황에서도 읽기와 쓰기 용량 모두에 대한 고가용성을 유지할 수 있습니다.

오토스케일링(Autoscaling)

오토스케일링은 사용 가능한 서버 집합에 인스턴스를 추가(스케일 아웃)하거나 제거(스케일 인)하는 수평 확장 기능입니다. EC2 인스턴스의 오토스케일링은 들어보셨겠지만, Aurora Read Replica에도 탄력성을 적용할 수 있다는 사실을 알고 계셨나요? 일반적으로 기본 부하를 처리할 최소 개수의 Read Replica를 구성하고, 수요 변화에 따라 인스턴스를 추가하거나 제거하는 오토스케일링 정책을 설정합니다. 이러한 탄력성 활용 능력 역시 스토리지 엔진이 데이터베이스 엔진과 분리되어 있기 때문에 가능한 것입니다.

유용한 예시로 B2B 전자상거래 사이트를 들 수 있습니다. 평일 업무 시간에는 트래픽이 몰리지만, 야간과 주말에는 매우 적습니다. 이미지와 상품 설명 콘텐츠는 읽기 비중이 높아 Read Replica와 오토스케일링 모두의 혜택을 받기에 적합합니다. Read Replica를 오토스케일링하면 피크 시간대의 수요를 충족하면서도 한가한 시간대에는 비용을 최소화할 수 있습니다.

리전 간 복제(Cross-Region Replication)

가용성을 한 단계 더 끌어올리고 싶다면 다른 리전으로 복제하세요. 데이터베이스 엔진이 데이터를 다른 리전에 복제하면 해당 리전에서 로컬로 읽거나, 기본 리전에 장애가 발생했을 때 활용할 수 있습니다. 보조 리전의 인스턴스는 Read Replica로 취급됩니다(멀티 마스터가 아님). 하지만 보조 리전 인스턴스 역시 자체적인 Read Replica를 둘 수 있고, 기본 리전 장애 시 마스터로 승격될 수도 있습니다.

리전 간 복제가 필요한 이유는 다양합니다. 때로는 데이터가 너무 중요해서 단일 지리적 리전에만 저장할 수 없는 경우도 있습니다. 이는 비즈니스 연속성, 규제 요건, 금융 관련 사유 때문일 수 있습니다. 또 다른 이유는 사용자와 데이터베이스 백엔드 간의 지연 시간(latency)을 줄이기 위함입니다. 다시 전자상거래를 예로 들면, 이미지와 상품 설명 변경 사항은 한 리전의 마스터에만 적용하면 되고, 전 세계로 분산되어 각 지역에서 로컬로 읽힙니다.

외부 복제(External Replication)

그렇다면 Aurora 클러스터 외부로 데이터를 내보내야 하는 상황은 어떨까요? 회사 정책이나 규제 환경상 요구되는 경우, 또는 Aurora 밖에서 데이터를 가공하거나 리포트를 생성해야 하는 경우가 있습니다. 이 모든 경우 External Replication으로 해결할 수 있습니다.

Aurora의 데이터를 Amazon EC2의 MySQL 인스턴스, 심지어 사내 데이터 센터에서 운영 중인 MySQL 인스턴스로 복제하는 것도 간단합니다. 이러한 단방향 복제를 통해 데이터는 항상 Aurora 클러스터와 동기화 상태를 유지하며, Aurora 외부에서도 활용 가능합니다.

서버리스(Serverless)

마지막으로 소개할 것은 서버리스입니다. 가용성과 확장성 측면에서 가장 의미 있는 발전 중 하나가 바로 서버리스의 등장입니다. 물론 서버리스가 서버가 없다는 뜻은 아닙니다. 서버의 프로비저닝, 구성, 스케일링, 유지 관리를 신경 쓸 필요가 없다는 의미입니다.

Aurora Serverless를 구성하려면 애플리케이션에 필요한 용량을 지정하기만 하면 됩니다. AWS가 클라이언트가 필요로 하는 순간에 해당 용량이 온디맨드로 제공되도록 세부 사항을 처리합니다. 서버리스에서는 기존의 데이터베이스 엔진과 스토리지 엔진 두 계층에 프록시(proxy) 계층이라는 추가 계층이 더해집니다.

AWS는 들어오는 요청을 수신하는 프록시 서버 플릿을 운영하며, 요청을 처리할 준비가 된 웜 풀(warm pool)의 DB 용량이 대기하고 있습니다. 첫 번째 쿼리가 들어오면 프록시 플릿이 이를 수신하고, 웜 풀에 인스턴스를 요청한 뒤, 할당이 완료되면 해당 인스턴스로 요청을 전달합니다. 더 좋은 점은 사용자에게 할당되는 인스턴스 수가 탄력적이라는 것입니다. 수요 변화와 Aurora Serverless 구성에서 지정한 한도에 따라 스케일 인/아웃됩니다. 앞선 전략들과 마찬가지로, 데이터베이스 엔진을 동적으로 할당할 수 있는 것은 데이터베이스와 스토리지의 분리 덕분입니다. 구성 설정에 따라 데이터베이스 인스턴스는 일정 시간 동안 사용자에게 할당된 상태로 즉시 사용 가능하게 유지되며, 타임아웃이 지나면 웜 풀로 반환됩니다. 과금은 실제 사용한 리소스에 대해서만 발생합니다. 인스턴스가 할당된 기간에는 인스턴스 비용과 소비된 스토리지 비용이 청구되고, 할당되지 않은 기간에는 소비된 스토리지 비용만 청구됩니다.

개발·테스트 환경처럼 트래픽 변동이 심한(spikey) 워크로드나, 사용 패턴을 예측할 히스토리가 부족한 신규 애플리케이션에는 서버리스가 최적의 선택입니다. 사용하지 않는 리소스에 대한 비용을 지불할 필요가 없고, 주말을 맞아 개발팀이 불필요한 리소스를 껐는지 확인할 걱정도 없으며, 사용자의 시간대가 본인의 수면 시간대와 겹친다는 이유로 한밤중에 용량을 조정하러 일어날 일도 없습니다.

마치며

Amazon Aurora는 처음부터 가용성, 내구성, 확장성을 염두에 두고 설계되었습니다. 표준 오픈소스 구현체처럼 사용해도 견고하고 안정적이며 성능이 뛰어난 데이터베이스를 얻을 수 있습니다. 하지만 Aurora의 기능과 이를 활용하는 패턴을 조금 더 깊이 이해한다면, 로컬 읽기 오프로딩부터 글로벌 분산 가용성까지, 요구사항에 맞는 솔루션을 구축할 수 있습니다.