Amazon Web Services 한국 블로그

Amazon Aurora 내부 들여다보기(2) – 쿼럼 읽기 및 상태 변경

이 글은 AWS Database Blog Amazon Aurora Under the Hood: Quorum Reads and Mutating State의 한국어 번역으로 AWS코리아의 최유정 솔루션즈 아키텍트가 번역해 주셨습니다.

지난 글에서 쿼럼 모델 적용 시 이점에 대해 설명했습니다. 특히 지연 시간이 비정상적으로 늘어나거나, 짧은 시간 동안 이용 불가능 한 경우 또는 장기간의 디스크 및 노드 손실의 경우, 쿼럼 모델을 적용한 시스템이 얼마나 복원력이 뛰어난 지에 대해 알아보았습니다. 이 시점에서 한 가지 의문이 들 수 있습니다—쿼럼이 그렇게 훌륭한 모델이라면, 왜 다른 시스템이 이를 사용하지 않을까요?

쿼럼 시스템 읽기 속도 지연
한 가지 이슈는 쿼럼 시스템에서 읽기 속도가 느려진다는 것입니다. 쿼럼 모델은 읽기 쿼럼과 쓰기 쿼럼에 최소한 하나의 구성원이 중첩 되야 합니다. 6개의 쿼럼을 갖는 Amazon Aurora 와 같은 시스템에서는 4개의 중복된 쓰기 쿼럼을 보장하기 위해 3개의 데이터 사본을 읽어야 합니다.

이는 비효율적입니다. 보통 데이터베이스 페이지를 읽을 때 버퍼 캐시에 없는 경우, SQL문은 I/O를 위해 대기하게 됩니다. 또한 3개의 데이터 사본을 읽어야 하지만, 특이하게 늘어난 지연 시간 및 간헐적인 가용성 이슈를 대응하기 위해 대략 5개를 읽어야 할 수 도 있습니다. 이 경우 네트워크에 부하를 주게 되며, 읽어야 할 데이터베이스 페이지들이 아주 많은 경우 읽기 작업이 대폭 늘어나게 됩니다. 쿼럼 읽기의 성능은 데이터를 모든 복사본에 저장하지만 이 중 1개의 데이터만 읽는 전통적인 복제 시스템과 비교하기 어렵습니다.

반면, Aurora는 쿼럼 쓰기 작업이 대폭 늘어나는 것을 방지합니다. 6개의 사본을 생성할 때 Aurora는 전체 데이터 페이지가 아닌, 로그 레코드만 사용합니다. 이전 버전의 데이터 페이지와 새로 전달 받은 로그를 사용하여 스토리지 노드 내에서 데이터 페이지들을 조합하고 비동기 방식으로 동작합니다. 그러나, 읽기 작업은 이처럼 동작하지 않습니다.

읽기 쿼럼의 오버헤드를 방지하는 방법
읽기 쿼럼의 오버헤드는 쿼럼 시스템의 명백한 단점입니다. 어떻게 하면 피할 수 있을까요? 해결 방법은 상태(State)를 이용하는 것입니다.

분산 시스템에서 상태 적용은 권고 사항이 아닙니다—노드를 확장하거나 이로 인해 장애 발생 시 일관된 상태를 관리하고 조정하는 것은 어려운 일이기 때문입니다. 물론 데이터베이스 시스템의 목적은 상태를 관리하고 데이터 원자성, 일관성, 격리 및 내구성(ACID)을 제공하는 것입니다. Aurora는 이러한 두 가지 기술 영역(분산 시스템과 데이터베이스 시스템) 모두를 다루고 있으며, Aurora 기술 혁신의 대부분은 한쪽 영역의 개념에서 출발하여 다른 쪽 영역의 개선을 도모하고 있습니다.

서로 간의 통신 없이 분산된 상태를 일치시키기 어렵지만, 데이터 확인, 조정 및 잠금 처리 없이 일관성을 유지할 수 있는 방법은 몇 가지가 있습니다. 여기서 살펴볼 구체적인 사례는 읽기 뷰(view)입니다. 많은 데이터베이스 시스템들이 유사한 개념을 가지고 있지만, MySQL에 초점을 맞추어 살펴보겠습니다.

MySQL은 모든 관계형 데이터베이스처럼 ACID를 제공합니다. 읽기 뷰는 SQL문 수행 시 커밋된 모든 변경사항은 볼 수 있고, 아직 커밋되지 않은 변경사항은 보지 못하게 하기 위한 논리적인 시점을 설정합니다. MySQL은 가장 최근 커밋의 로그시퀀스번호(LSN)을 설정하여 이를 구현하며, 이러한 방식을 통해 이미 커밋된 모든 변경사항들은 조회 가능하게 하고, 조회되지 말아야 할 변경사항들은 활성 트랜잭션 리스트를 사용하여 확인합니다. 특정 읽기 뷰를 가진 SQL문이 데이터 페이지를 조회할 때, 읽기 뷰 생성 당시 활성화된 트랜잭션들의 변경 사항은 조회되지 말아야 합니다. 이는 변경 사항이 현재 커밋되었거나 읽기 시점 커밋 LSN 이후에 시작된 어떠한 트랜잭션들에 대해서도 동일하게 적용됩니다. 트랜잭션이 읽기 뷰를 생성하면, 시스템 내 발생한 모든 다른 변경 사항들로부터 격리될 수 있습니다. —일관된 특정 시점을 참조할 수 있습니다.

위의 사항은 읽기 쿼럼과 모든 점에서 연관 관계가 있습니다. 데이터베이스는 변경 사항을 지속적으로 스토리지 노드에 저장합니다. 개별 변경 사항은 4번의 쓰기 완료 응답을 받은 후에 영구적으로 저장 완료로 표기합니다. 볼륨의 특정 시점이 영구적이기 위하여 해당 시점 이전에 발생한 개별 변경 사항이 각각 영구적으로 저장되어야 합니다. 이러한 작업을 위해서는, 어떤 스토리지 노드가 쓰기 요청에 대해 완료 응답을 보냈고 어떤 스토리지에서 해당 변경 사항들을 조회할 수 있는지 알아야 합니다. 읽기 요청 시, 해당 요청은 데이터베이스가 확인해야 할 읽기 시점 커밋 LSN를 갖고 있습니다. 데이터베이스는 해당 읽기 시점 커밋 LSN에 해당하거나 그 이후 데이터가 존재하는 스토리지 노드로 읽기 요청을 전달합니다.

이런 방식은 쿼럼 읽기를 피하기 위해 상태 정보를 저장하게 되며, 필요한 데이터 버전이 위치한 노드로부터 데이터를 읽어올 수 있어 네트워크, 스토리지 노드 및 데이터베이스 노드의 부하를 상당 부분 감소시킬 수 있습니다.

지연 시간을 줄이는 방법
읽기 쿼럼 문제를 피하더라도, 이로 인해 단일 스토리지 노드에서 지연시간 이슈가 발생할 수 있습니다. 따라서, Aurora는 스토리지 노드의 읽기 요청 응답 시간을 추적하여 관리하고, 현재 가장 짧은 응답 시간을 제공하는 스토리지 노드를 조회하며, 경우에 따라 다른 노드를 하나 더 추가 조회하여 응답 시간 정보를 최신 상태로 유지하게 됩니다.

단일 데이터베이스인 경우에는 모든 쓰기 작업을 확인하고 읽기 작업을 조정할 수 있어 매우 간단하지만, 읽기 전용 복제본(Read-replica)이 있는 경우는 좀 더 복잡합니다. Aurora의 읽기 전용 복제본은 마스터 데이터베이스 노드와 동일한 스토리지 볼륨을 공유하며, 마스터의 실행 로그를 비동기로 전달받아 캐시내 데이터 페이지를 갱신합니다. 이런 방식은 읽기 복제본을 데이터 유실이나 동기식 복제의 쓰기 지연 시간없이 마스터 노드로 승격시킬 수 있을 뿐 아니라 비용도 줄여줍니다. 쓰기 마스터 노드에서 커밋된 모든 변경사항을 복제본으로 미처 전파되지 않았더라도 영구적으로 저장됩니다. 그러므로 복제 노드들은 독자적으로 읽기를 수행할 때 읽어야 할 데이터의 쓰기 및 쓰기 완료 응답 등의 현황에 대해 알 수 없습니다.

따라서, 마스터에서 복제본으로 실행 레코드들을 전달할 때 읽기 뷰와 개념적으로 동일한 기능을 함께 제공합니다. 이러한 뷰는 커밋 LSN과 어떤 세그먼트들이 어떤 LSN로 영구 저장 되었는지의 정보를 반영합니다. 일반적으로 커밋 LSN는 10 밀리초마다 반영될 수 있으므로, 복제본들은 최소한의 조정으로 마스터 노드와 거의 동일한 정보를 제공할 수 있습니다.

파괴적(destructive) 쓰기 방지
읽기 노드와 쓰기 노드간에 트래픽을 조율하고자 하는 가장 큰 이유는 읽고자 하는 데이터의 가시성을 보장하기 위해서 입니다. 읽기 뷰는 이런 조율작업을 크게 줄여줍니다.—페이지의 이전 이미지로 돌아가고자 하는 경우. Aurora는 쓰기 작업 시 데이터 페이지들을 별도의 공간에 작성합니다. 해당 데이터 페이지들이 모두 백업되고 전체 읽기 노드들이 해당 버전의 읽기 시점을 볼 수 있게 되면, 이전 버전에 대해 가비지 콜렉션(garbage-collect) 작업을 하게 됩니다. 이러한 방식으로 복제 노드들은 마스터 노드에 이어 수 밀리초 간격으로 구조적으로 일관된 데이터베이스 뷰를 제공할 수 있습니다.

관계형 데이터베이스의 핵심인 실행 로그(Redo log)는 트랜잭션이 롤백(Roll-back) 되더라도 항상 증가하게 됩니다. 데이터베이스를 구성하는 데이터 페이지들은 실행 로그가 반영된 특정 시점의 캐시된 형상(point-in-time cached instantiations)이라고 볼 수 있습니다. 대부분의 데이터베이스가 데이터 페이지를 파괴적으로 작성하는 것은 관계형 데이터베이스가 처음 생길 당시 높은 디스크 비용으로 인한 것입니다.

Aurora는 앞서 설명했듯이 실제로 읽기 쿼럼을 조회하지 않고, 마스터 데이터베이스 노드의 캐시된 상태를 확인할 수 없는 경우만 읽기 쿼럼을 조회하는데, 이는 마스터 인스턴스를 재시작하거나 복제본을 마스터로 승격 시 로컬 상태를 다시 설정해야 하는 경우에 해당됩니다. 어떤 트랜잭션들이 커밋되었는지 확인하기 위해 필요한 작업이며, 향후에 블로그에서 살펴보겠습니다. 데이터베이스 장애가 읽기 작업보다는 덜 빈번하게 발생함으로, 이러한 트레이드오프는 고려할 가치가 있습니다.

요약
두 차례 글을 통해, 가용성을 위해 어떻게 쿼럼을 사용하고 전통적인 읽기 쿼럼의 오버헤드를 회피하는지에 대해 살펴봤습니다. 다음 글에서는, 쿼럼 시스템을 어떻게 합리적인 가격으로 구성했는지에 대해 살펴보겠습니다. 질문이나 블로그에서 다뤄지길 바라는 주제가 있으면, aurora-pm@amazon.com 로 연락을 주십시오.

– Anurag Gupta;

전체 목록

  1. Amazon Aurora 내부 들여다보기(1) – 쿼럼 및 상관 오류 해결 방법
  2. Amazon Aurora 내부 들여다보기(2) – 쿼럼 읽기 및 상태 변경
  3. Amazon Aurora 내부 들여다보기(3) – 쿼럼 집합을 이용한 비용 절감 방법
  4. Amazon Aurora 내부 들여다보기(4) – 쿼럼 구성원
  5. Amazon Aurora 내부 들여다보기(5) – Fast DDL