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

Amazon Aurora 엔드포인트 완벽 가이드: 클러스터·리더·인스턴스 엔드포인트 활용법

Aurora 읽기 복제본(Read Replica)을 사용해 본 적이 있다면 여러 종류의 엔드포인트가 제공된다는 것을 눈치챘을 것입니다. 클러스터 엔드포인트, 리더 엔드포인트, 인스턴스 엔드포인트까지... 이렇게 다양한 선택지가 있을 때 어떤 상황에서 무엇을 사용해야 할까요? 다소 복잡한 시스템에서 늘 그렇듯, 답은 "상황에 따라 다르다"입니다. 이 글에서는 각 엔드포인트의 특징과 사용 사례, 그리고 설계 결정에 따른 트레이드오프를 살펴보겠습니다.

먼저 Amazon Aurora에서 제공하는 엔드포인트의 종류를 간단히 짚어보겠습니다.

  • 클러스터 엔드포인트(Cluster Endpoint) – 애플리케이션을 DB 클러스터의 현재 기본(Primary) DB 인스턴스에 연결합니다. 이 인스턴스를 통해 읽기와 쓰기를 모두 수행할 수 있습니다.

  • 리더 엔드포인트(Reader Endpoint) – 사용 가능한 읽기 복제본 풀 전체에 연결을 로드 밸런싱합니다. 읽기 쿼리를 이곳으로 오프로드하면 기본 DB 인스턴스의 부담을 줄일 수 있습니다.

  • 인스턴스 엔드포인트(Instance Endpoint) – 클러스터 내 특정 인스턴스에 직접 연결합니다. Amazon Aurora가 자동으로 연결을 분배하도록 두는 대신, 클라이언트가 쿼리 할당을 세밀하게 제어할 수 있습니다.

"쓰기는 클러스터 엔드포인트로, 모든 읽기는 리더 엔드포인트로 보내면 되고, 굳이 특정 인스턴스에 직접 연결할 일은 없지 않나? 내장된 장애 조치(failover)를 우회하는 것이니 오히려 위험하지 않을까?"라고 생각하실 수 있습니다. 하지만 앞서 언급했듯이, 애플리케이션과 Aurora의 상호작용은 하나의 복잡한 시스템을 이룹니다. 복잡한 시스템에는 만능 해법이 통하지 않습니다... 새벽에 걸려오는 장애 대응 전화를 즐기지 않으신다면 말이죠.

지금부터 몇 가지 시나리오를 통해 각 엔드포인트를 언제, 어디에 활용해야 하는지 살펴보겠습니다.

즉시 일관성(Immediate Consistency)

일부 애플리케이션은 데이터가 즉시 일관성을 유지할 것으로 기대합니다. 이런 애플리케이션은 데이터를 쓴 직후 바로 읽으며, "로컬 데이터가 아닌 모델을 신뢰하라"는 설계 패턴을 엄격히 따릅니다. Amazon Aurora는 ACID를 준수하므로, 클러스터 엔드포인트로 성공적인 쓰기 커밋 직후 읽기를 수행하면 예상한 데이터를 반환합니다(다른 트랜잭션이 그 사이에 데이터를 수정하지 않았다는 전제하에).

문제가 발생하는 지점은 쓰기는 클러스터 엔드포인트로, 읽기는 리더 엔드포인트로 보낼 때입니다. 데이터가 기록된 후 읽기 측에 반영되기까지 지연(latency)이 존재하기 때문입니다. 복제 지연은 100밀리초 미만이지만 순간적이지는 않아 경합 조건(race condition)이 발생할 수 있습니다. 쓰기 직후 즉시 읽어야 하는 시나리오라면 읽기와 쓰기 모두 클러스터 엔드포인트를 사용하세요. 참고로 추가 성능이 필요하다면 기본 인스턴스의 크기를 확장해야 합니다.

반면 최종 일관성(eventual consistency)으로 충분하고 애플리케이션이 이를 지원한다면, 리더 엔드포인트를 활용해 기본 인스턴스의 부하를 크게 줄일 수 있습니다.

읽기 부하 분산(Offloading Reads)

쓰기 직후 즉시 읽기가 불가능하다면 리더 엔드포인트를 별도로 둘 필요가 있을까요? 사실 약간의 비일관성이 문제되지 않는 사용 사례가 많습니다. 예를 들어 일일 보고 작업의 경우, 어제 데이터로 배치 잡을 돌려 리포트를 생성할 때 100밀리초의 복제 지연은 전혀 문제가 되지 않습니다. 이커머스 사이트의 상품 설명 같은 경우도 마찬가지입니다... 사용자 브라우저에 남아 있는 데이터가 이미 오래된 경우가 많아, 복제 지연의 영향을 받을 가능성은 더 낮습니다.

일반적으로 즉시 일관성에 의존하지 않는 읽기 중심(read-heavy) 워크로드라면 리더 엔드포인트 사용을 고려하는 것이 좋습니다.

비균등 워크로드(Non-uniform Workloads)

인스턴스 엔드포인트를 사용하는 것이 합리적인 상황도 있습니다. Elastic Load Balancer 뒤에 여러 개의 스테이트리스(stateless) 마이크로서비스가 있는 애플리케이션을 생각해 봅시다. 이 경우 쿼리가 클라이언트 전반에 고르게 분산되고, 따라서 리더 엔드포인트 사용 시 읽기 복제본에도 균등하게 분배된다고 가정하는 것이 자연스럽습니다.

그렇다면 각 클라이언트의 워크로드가 균등하지 않다면 어떨까요? 예컨대 리포팅 서비스가 추가되면 특정 읽기 복제본 하나가 나머지에 비해 과도하게 높은 부하를 받게 됩니다. 앞서 언급한 마이크로서비스들도 이 복제본을 함께 사용한다면, 리포팅 서비스가 사용하는 인스턴스에 쿼리할 때 성능 저하가 발생할 가능성이 높습니다. 이를 피하는 한 가지 방법은 Amazon Aurora에게 맡기지 않고 클라이언트 측에서 연결 분배를 직접 관리하는 것입니다. 다행히 이는 리더 엔드포인트 대신 인스턴스 엔드포인트를 사용하면 손쉽게 구현할 수 있습니다. Aurora MySQL용 MariaDB Connector/J 또는 Amazon Aurora PostgreSQL의 Fast Failover 기능을 활용하면, 드라이버가 읽기 복제본으로 사용할 개별 인스턴스를 인식하고 쿼리 분배 방식을 직접 관리할 수 있습니다.

DNS 캐싱 관리

워크로드의 특성을 이해하는 것 못지않게, Aurora의 고가용성(HA)과 리더 엔드포인트 로드 밸런싱이 연결을 어떻게 할당하는지 이해하는 것도 중요합니다.

클러스터 엔드포인트의 자동 장애 조치와 리더 엔드포인트의 로드 밸런싱은 IP, TCP 또는 데이터베이스 클라이언트 프로토콜 계층이 아닌 DNS(Amazon Route 53)를 통해 처리됩니다. DNS로 연결 분배를 처리하기 때문에 애플리케이션은 새 연결 요청마다 DNS 조회를 수행해야 합니다. DNS 캐싱을 사용하는 애플리케이션은 캐시 타임아웃을 Amazon Aurora의 DNS 레코드 TTL에 맞춰 조정해야 합니다. TTL보다 오래 DNS 응답을 캐싱하면 몇 가지 오류 상황이 발생합니다. 고가용성(HA) 장애 조치 이벤트, 즉 읽기 복제본이 기본 인스턴스로 승격되는 상황에서 캐시된 DNS 응답은 애플리케이션이 실패한 기존 인스턴스에 재접속을 시도하게 만듭니다. 리더 엔드포인트의 경우 DNS 응답을 캐싱하면 연결이 사용 가능한 복제본들에 골고루 분산되지 않고 특정 읽기 복제본에 몰리게 됩니다.

마무리

지금까지 살펴본 것처럼, 실제 프로덕션 워크로드에는 만능 해법이 없습니다. 애플리케이션에 즉시 일관성이 필요하다면 읽기와 쓰기 모두 클러스터 엔드포인트로 보내야 합니다. 읽기 쿼리가 약간의 복제 지연을 감당할 수 있다면 리더 엔드포인트로 읽기 부하를 분산하세요. 읽기 복제본을 사용할 수 있지만 쿼리가 모든 클라이언트에 균등하게 분산되지 않는다면 인스턴스 엔드포인트를 사용하고 클라이언트 측에서 연결 분배를 관리하세요. 그리고 잊지 말아야 할 점은, 애플리케이션이 DNS 레코드 TTL보다 긴 타임아웃으로 DNS 캐싱을 사용한다면 클러스터 엔드포인트 HA 장애 조치 중이나 리더 엔드포인트 사용 시 엔드포인트가 기대대로 동작하지 않을 수 있다는 것입니다.

애플리케이션의 특성을 이해하고, Aurora 엔드포인트의 동작 방식을 파악하며, 이를 올바르게 적용하면 더 견고한 애플리케이션 환경을 구축할 수 있습니다. 이는 여러분과 고객 모두에게 매우 중요한 부분입니다. 누구도 새벽에 걸려오는 장애 대응 전화를 원하지 않으니까요.

의견이나 질문이 있다면 피드백 탭을 이용해 주세요.