Couchbase에서 지연 시간과 처리량은 데이터 복제에 의해 크게 영향을 받습니다.

데이터 복제 모델에는 주로 마스터-슬레이브(카우치베이스, 몽고DB, 에스프레소), 마스터-마스터(PostgreSQL용 BDR, 오라클용 골든게이트), 마스터리스(Dynamo, 카산드라) 등 다양한 종류가 있습니다. 이 문서에서는 키-값(KV) 저장소의 마스터-슬레이브 복제에 대해서만 설명합니다.

Master Slave Replication Couchbase

마스터-슬레이브 복제 모델에서는 단일 데이터 파티션에 대해 하나의 마스터와 하나 이상의 복제본이 있으며, 복제본은 기본적으로 슬레이브로서 마스터 파티션의 데이터를 따릅니다. 클라이언트 애플리케이션은 키 값을 마스터로 전송하고, 이후 마스터에서 복제본으로 키 값을 전송합니다.

이 글은 순서 지정, 단조롭게 증가하는 시퀀스 번호, 스냅샷, 쓰기만 추가하기 및 압축을 사용하는 MVCC와 같은 몇 가지 개념으로 시작합니다. 그런 다음 이 문서에서는 마스터-슬레이브 복제를 (1)을 사용하여 수행하는 방법을 설명합니다. 델타 스냅샷 또는 (2) 특정 시점 스냅샷의 장단점, 그리고 어느 쪽을 사용하는 것이 가장 좋은지에 대해 설명합니다. 마지막으로, 인기 있는 빅데이터 플랫폼인 Couchbase가 데이터 복제를 위해 스냅샷을 어떻게 사용하는지 간략하게 설명합니다.

데이터를 파티션하고, 파티션을 물리적 노드에 할당하고, 노드 장애를 감지 및 처리하고, 서로 다른 데이터 브랜치를 조정하는 등의 작업은 분산된 KV 저장소를 강화하는 데 중요합니다. 이 문서에서는 이 중 어느 것도 다루지 않고 단일 데이터 파티션의 마스터-슬레이브 복제, 특히 카우치베이스와 복제에 대해서만 설명합니다.

배경

나이브 복제

데이터를 복제하는 한 가지 방법은 복사본을 원할 때마다 원본의 전체 복사본을 가져오는 것입니다. 이 방법은 구현이 매우 간단하지만, 복제본이 실시간으로 업데이트를 가져올 수 없기 때문에 원본 데이터가 계속 새로운 업데이트를 받는 실시간 워크로드가 있는 OLTP 데이터베이스나 KV 저장소에서는 그다지 유용하지 않습니다.

변경 사항(델타)만 전송하는 재개 기능은 대량의 데이터를 자주 처리해야 하는 모든 복제 프로토콜에 중요한 기능입니다. 그러나 다음 섹션에서 설명하는 주문 및 스냅샷의 필요성에 대한 추가적인 복잡성이라는 대가가 따릅니다.

시퀀스 번호로 주문하기

순서는 애플리케이션이 데이터의 인과 관계를 추론할 수 있게 해주며, 다시 말해 애플리케이션이 어떤 작업이 다른 작업의 이전 또는 이후에 발생했는지 알 수 있게 해주므로 중요합니다. KV 스토어에서 순서는 스토어에서 주어진 키의 최신 값을 식별하는 데 사용되며, 스토어에서 키가 수신되는 순서도 나타냅니다. 단조롭게 증가하는 시퀀스 번호는 스토어에서 키-값에 대한 '순서'를 얻는 한 가지 방법입니다. 스토어에 있는 모든 키-값 쌍에는 고유한 시퀀스 번호가 연결되어 있으며, 스토어에 새 키-값이 수신되면 해당 시퀀스는 단조롭게 증가합니다.

 

운영 KEY VALUE 시퀀스 번호
삽입 K1 V1 SEQ1
삽입 K2 V2 SEQ2
업데이트 K1 V1' SEQ3
삽입 K3 V3 SEQ4

 

위의 예에서 K2-V2는 K1-V1 다음에 스토어에서 수신하고, K1-V1'은 K2-V2 다음에 스토어에서 수신하는 식으로 수신합니다. 따라서 SEQ4 > SEQ3 > SEQ2 > SEQ1입니다. 스토어가 애드만 있는 경우 SEQ3 > SEQ1을 사용하면 K1의 (최신) 값이 V1이 아니라 V1'임을 확인할 수 있습니다.

단조롭게 증가하는 시퀀스 번호의 사용은 주로 나중에 설명하는 특정 시점 스냅샷에서 주로 사용됩니다.

스냅샷

가장 기본적인 의미에서 스냅샷(전체 스냅샷)은 인스턴스에서 KV 저장소에 대한 변경 불가능한 보기입니다. 이는 또한 해당 인스턴스의 KV 저장소에 대한 일관된 보기이기도 합니다.

우리는 "델타 스냅샷"를 일정 기간 동안 KV 저장소에서 수신한 키-값 쌍의 불변 복사본으로 저장합니다. 이 스냅샷은 저장소의 모든 키-값을 포함하지 않고 바로 앞의 델타 스냅샷이 생성된 후 현재 스냅샷이 생성되는 시점까지 수신된 키-값만 포함하기 때문에 델타 스냅샷이라고 부릅니다. 연속적인 델타 스냅샷은 특정 시점까지, 즉 마지막 스냅샷이 생성되는 시점까지 KV 저장소에 대한 일관된 보기를 제공합니다.

추가 전용 쓰기를 사용하는 MVCC

다중 버전 동시성 제어(MVCC)는 KV 스토어에서 동시 읽기 및 쓰기를 활성화하기 위해 사용되는 동시성 제어 방법입니다. 동시성을 처리하는 가장 간단한 방법은 읽기-쓰기 잠금을 사용하는 것입니다. 하지만 방대한 양의 데이터를 처리하는 분산형 KV 저장소의 경우, MVCC가 잠금보다 매우 유용하다는 것이 입증되었습니다. MVCC는 읽기 및 쓰기 처리량을 높이고 지연 시간을 단축하는 데 도움이 됩니다.

MVCC는 스냅샷을 사용하여 달성되며 KV 스토어에 쓰기만 추가합니다. 아래 예시에서는 델타 스냅샷 1에 리더가 있는 동안 '키 B'가 쓰기에 의해 업데이트된다고 가정해 보겠습니다. 잠금을 통한 동시성 제어는 전체 스냅샷의 복제가 완료될 때까지 변경하는 엔티티가 기다려야 합니다. 그러나 추가 전용 MVCC 접근 방식을 사용하면 현재 스냅샷을 읽는 동안에도 키 B에 대한 쓰기가 계속 진행될 수 있습니다.

고급 독자를 위해 KV 스토어가 더 복잡한 데이터 구조를 사용하여 데이터를 저장하는 경우에도 MVCC를 수행할 수 있습니다. 아래 예시는 B+Tree만 추가할 때 MVCC를 수행하는 방법을 보여줍니다. 현재 델타 스냅샷에 리더가 있는 동안 '키 B'가 작성자에 의해 업데이트되었다고 가정해 보겠습니다.

추가 전용 MVCC 접근 방식을 사용하면 아래와 같이 현재 스냅샷을 읽고 있는 동안에도 '키 B'와 B+Tree의 관련 브랜치에 대한 쓰기가 계속 발생할 수 있습니다.

G와 G'의 B+Tree 루트로 표시된 두 개의 겹치는 스냅샷은 두 시점의 KV 스토어에 대한 일관된 뷰를 나타냅니다.

압축

스냅샷은 변경 불가능하기 때문에 키에 대한 업데이트는 KV 저장소의 끝에만 추가되므로 저장소의 메모리 사용량은 결국 활성 키 값에 필요한 메모리보다 훨씬 많아지게 됩니다. 따라서 KV 저장소는 압축이라는 백그라운드 작업을 통해 주기적으로 이전 스냅샷을 병합하고 중복되거나 오래된 키값을 제거해야 합니다. 압축은 KV 저장소에서 사용하는 메모리를 줄입니다.

압축 트리거는 메모리 임계값 또는 고정 시간 간격 또는 이 두 가지를 조합하여 설정할 수 있습니다.

델타 스냅샷

KV 스토어는 일련의 연속적인 델타 스냅샷을 전송하여 복제할 수 있습니다. 위에서 설명한 대로, 추가 전용 쓰기 방식에서는 새로운 키 값과 업데이트만 스토어에 추가됩니다. 항목 배치를 수신하면 변경 불가능한 스냅샷이 생성되고 복제 노드로 전송할 준비가 완료됩니다. 이 스냅샷이 생성된 후 스토어에서 수신한 키 값은 스토어에 추가되며 다음 스냅샷의 일부가 됩니다. 그러면 복제 클라이언트는 이러한 변경 불가능한 델타 스냅샷을 차례로 가져와 소스와 일치하는 스토어 보기를 얻습니다. 모든 KV 쌍에 대해 시퀀스 번호가 필요하지는 않지만 델타 스냅샷의 순서를 식별해야 한다는 점에 유의하세요.

이 접근 방식의 한 가지 단점은 KV 저장소의 소스 측에서 여러 개의 변경 불가능한 델타 스냅샷을 하나의 스냅샷으로 압축할 수 있다는 것입니다. 이제 복제 클라이언트가 마지막으로 압축된 스냅샷을 받기 전에 압축이 발생하면 클라이언트는 스냅샷의 시작부터 완전히 압축된 스냅샷을 수신해야 합니다. 5개의 변경 불가능한 델타 스냅샷 스냅1, 스냅2, 스냅3, 스냅4가 있고 클라이언트가 스냅3까지 수신한 후 압축이 실행되고 소스 측의 스냅샷 4개가 모두 하나의 스냅샷 스냅1'로 압축된다고 가정해 보겠습니다. 이제 클라이언트는 snp3에서 다시 시작할 수 없으며, 이전에 받은 스냅샷(snp3까지)을 롤백하고 snp1'을 완전히 수신해야 합니다.

모든 키-값 쌍에 시퀀스 번호(단조롭게 증가하는)를 부여한 다음 네트워크를 통해 snp3의 snap_end보다 큰 시퀀스 번호만 전송하는 방식으로 최적화를 수행할 수 있습니다. 그러나 KV 저장소는 여전히 snp3의 snap_end에 도달하기 위해 snp1'의 시작부터 읽어야 합니다.

이 접근 방식의 또 다른 단점은 최신 키-값 쌍이 불변의 델타 스냅샷으로 형성될 때까지 복제할 수 없다는 것입니다. 따라서 복제본으로 전송되는 키의 대기 시간이 늘어납니다.

델타 스냅샷은 상당히 많은 양의 항목을 복제하는 데 유용합니다, 처리량은 높지만 지연 시간도 높습니다..

특정 시점 스냅샷

특정 시점 스냅샷은 즉석에서 생성되는 스냅샷입니다. 즉, 새로운 데이터와 업데이트가 KV 스토어에 기록되는 동안 복제 클라이언트가 데이터를 요청하면 스토어에서 스냅샷을 생성합니다. 이는 최신 키 값을 받기 위해 복제본이 소스에서 스냅샷이 생성될 때까지 기다릴 필요가 없음을 의미합니다.

특정 시점 스냅샷은 추가 전용 KV 스토어에서 매우 빠르게 생성할 수 있으며(지연 시간이 짧음), 항목의 인메모리, 정상 상태 복제에 가장 적합합니다. 여기서 정상 상태란 모든 복제 클라이언트가 소스를 거의 따라잡은 상태를 의미합니다.

이 모델에서는 모든 키-값 쌍에 단조롭게 증가하는 시퀀스 번호가 있어야 합니다. 특정 시점 스냅샷은 튜플 {start_seqno, end_seqno}로 정의됩니다.

소스에 시퀀스 번호 0부터 100까지의 키-값 쌍이 있고 복제 클라이언트 R1이 데이터 복사본을 요청한다고 가정해 보겠습니다. 시퀀스 번호 0부터 100까지의 키-값 쌍이 스냅샷(특정 시점 스냅샷)으로 R1에 전송되고 클라이언트 R1에 해당하는 커서 C1이 스토어에 표시됩니다. 나중에 스토어에 KV 쌍이 20개 더 추가되어 가장 높은 시퀀스 번호가 120이라고 가정해 보겠습니다. 다른 클라이언트 R2가 데이터를 요청하면 시퀀스 번호 0에서 120까지의 키-값 쌍이 R2에 스냅샷으로 전송되고 클라이언트 R2에 해당하는 커서 C2가 스토어에 표시됩니다. 시퀀스 번호 150까지 더 많은 데이터가 스토어에 추가되면 클라이언트 R1은 101에서 150까지, 클라이언트 R2는 121에서 150까지 연속적인 시점 스냅샷에서 150까지 가져올 수 있습니다. 커서 C1과 C2는 클라이언트 R1과 R2가 이전에 떠났던 위치에서 빠르게 다시 시작하는 데 중요합니다. 커서가 이동함에 따라 커서가 표시된 시퀀스 번호보다 작은 시퀀스 번호를 가진 키-값 쌍은 읽기-쓰기 경합 없이 압축되거나 메모리에서 제거될 수 있습니다(영구 KV 저장소에서 인메모리 데이터 복제를 사용하는 경우).

특정 시점 스냅샷은 복제 클라이언트가 필요에 따라 생성되는 자체 스냅샷을 가져와서 스냅샷이 생성될 때까지 기다릴 필요가 없으므로 정상 상태 복제에 적합합니다. 따라서 클라이언트는 가능한 한 빨리 최신 키-값 쌍을 전송받아 소스를 매우 빠르게 따라잡을 수 있습니다. 연속된 스냅샷 사이에 압축이 실행되는 경우 추가 클라이언트가 다시 시작할 필요가 없으며, 소스도 모든 클라이언트가 읽을 수 있도록 델타 스냅샷을 보관할 필요가 없습니다.

느린 클라이언트와 지연(지연) 클라이언트는 특정 시점 스냅샷에서 잘 작동하지 않습니다. 읽기-쓰기 경합 없이 압축하거나 시퀀스 번호가 가장 적은 커서의 시퀀스 번호보다 작은 키-값 쌍을 메모리에서 꺼낼 수 없기 때문에 느린 클라이언트 하나가 있으면 다른 모든 클라이언트의 특정 시점 스냅샷 생성 속도가 느려지고 메모리 사용량도 증가할 수 있습니다.

특정 시점 스냅샷은 최신 항목을 빠르게 복제하는 데 유용합니다, 지연 시간은 짧지만 처리량도 낮습니다..

델타 및 특정 시점 스냅샷 모두 사용

둘 다 높은 처리량과 짧은 지연 시간 파티션을 복제하는 동안 필요에 따라 델타 스냅샷 모드 또는 특정 시점 스냅샷 모드를 동적으로 전환하여 수행할 수 있습니다.

복제 클라이언트가 소스에 연결하면 처음에는 높은 처리량으로 델타 스냅샷을 가져와서 소스를 곧 따라잡아 정상 상태에 도달합니다. 그런 다음 복제가 특정 시점 스냅샷 모드로 전환되어 클라이언트는 매우 짧은 지연 시간으로 최신 항목을 계속 가져옵니다. 어떤 이유로 클라이언트가 느려지면 복제는 증분 델타 스냅샷 모드로 다시 전환되어 비정상적인 메모리 사용량 증가를 줄입니다. 그리고 느린 클라이언트가 소스를 따라잡고 다시 정상 상태에 도달하면 복제는 특정 시점 스냅샷 모드로 전환됩니다.

기타 디자인 고려 사항

삭제 삭제

추가 전용 모드에서는 삭제가 항상 스토어 끝에 추가됩니다. 스냅샷을 사용하는 복제에서는 모든 복제본에서 삭제되는 키를 반영하기 위해 삭제 추가가 필수적입니다. 그러나 삭제는 스토리지 메모리에 대한 오버헤드이므로 영원히 보관할 수는 없습니다. 따라서 결국 삭제는 제거되어야 합니다.

그러나 삭제 제거는 느린 복제 클라이언트에 영향을 미칠 수 있으며, 특히 삭제가 제거된 스냅샷을 따라잡지 못한 클라이언트의 경우 증분 복제가 중단될 수 있습니다. 이러한 클라이언트는 원본과 일치하는 사본을 얻기 위해 모든 스냅샷을 처음부터 다시 빌드해야 할 수도 있습니다.

분기

하드 장애가 발생하면 복제본 간에 서로 다른 데이터 브랜치가 발생할 수 있습니다. 이러한 브랜치를 조정하면 모든 복제본이 결국에는 동일한 복제본을 갖게 될 수 있습니다. 이를 위한 프로토콜과 알고리즘이 있으며, 이는 스냅샷 세계와 매우 잘 맞닿아 있습니다. 그러나 이 글의 범위에서 벗어나 있습니다. 이 문서에서는 심각한 장애가 없는 경우에만 복제 및 스냅샷 방식에 대해 설명합니다.

중복 제거

중복 제거는 스냅샷에서 동일한 키의 중복 버전을 제거하고 해당 스냅샷에 최종 버전의 키만 유지하는 것입니다. 중복 제거의 주된 목적은 메모리 사용량을 줄이는 것입니다.

중복 제거는 압축하는 동안 델타 스냅샷에서 수행됩니다. 특정 시점 스냅샷에서는 압축하는 동안은 물론 항목이 추가되는 동안에도 중복 제거를 수행할 수 있습니다. 특정 시점 스냅샷과 함께 중복 제거를 수행하면 특정 시점 스냅샷을 읽을 때 쓸 수 없고 장애 발생 시 클라이언트의 소스가 변경될 때 재개할 수 없는 등의 추가적인 복잡성이 발생합니다. 앞서 언급했듯이 이러한 장애 시나리오에 대한 논의는 이 글의 범위를 벗어납니다.

카우치베이스에서의 사용

Couchbase에서는 디스크의 델타 스냅샷 또는 메모리의 특정 시점 스냅샷을 동적으로 선택하는 복제를 통해 지연 시간과 처리량을 개선할 수 있습니다. 또한 디스크의 델타 스냅샷은 단조롭게 증가하는 시퀀스 번호를 사용하여 클라이언트가 중단한 지점부터 다시 시작하여 네트워크 트래픽을 줄입니다.

Couchbase는 또한 중복 제거, 노드 장애 감지 및 처리, 다양한 데이터 브랜치의 조정, 단순한 복제 클라이언트보다 더 정교한 데이터 클라이언트 제공(인덱싱, 전체 텍스트 검색), 캐싱, 파티셔닝 등을 통해 고가용성, 고성능 및 메모리 우선 데이터 플랫폼을 제공하는 데 중요한 기능을 수행합니다.

결론

마스터-슬레이브 복제에서 '델타 스냅샷'은 항목 배치를 복제하는 데 적합하므로 처리량이 높습니다. '특정 시점 스냅샷'은 정상 상태 복제에 적합하므로 지연 시간이 짧습니다. 상황에 따라 둘 중 하나를 사용하면 처리량이 높고 지연 시간이 짧은 마스터-슬레이브 복제를 얻을 수 있습니다.

작성자

Sundar Sridharan

순다르 스리다란, 수석 소프트웨어 엔지니어

작성자

게시자 순다르 스리다란

순다르 스리드하란은 거의 5년 동안 카우치베이스에서 근무한 선임 소프트웨어 엔지니어입니다. 순다르 스리다란은 최종 지속성 엔진의 개발을 담당하고 있습니다. 카우치베이스에 입사하기 전에는 오라클에서 5년 동안 오라클의 EXADATA 서버 제품을 담당했습니다.

댓글 남기기