Skip to main content

5. 복제

복제란, 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지한다는 의미입니다. 이가 필요한 이유는 다음과 같습니다.

  • 지리적으로 사용자와 가깝게 데이터를 유지해 지연 시간을 줄입니다.
  • 시스템의 일부에 장애가 발생해도 지속적으로 동작할 수 있게 해 사용성을 높입니다.
  • 읽기 질의를 제공하는 장비의 수를 확장해 읽기 처리량을 늘립니다.

5장에서는 데이터셋이 작다고 가정한 경우, 6장에는 그 데이터가 단일 장비에 넣기에는 너무 커서 파티셔닝(샤딩 )에 대해 이야기 합니다.

복제에서의 어려움은 복제된 데이터의 변경 처리에 있으며 대표적으로 유명한 알고리즘은 다음과 같습니다.

  • 단일 리더(single-leader) 복제
  • 다중 리더(multi-leader) 복제
  • 리더 없는(leaderless) 복제

모든 분산 데이터베이스는 세 가지 방법 중 하나를 사용하며 각각의 장단점이 있습니다.

리더와 팔로워#

  • 데이터베이스의 복사본을 전달하는 각 노드를 복제 서버(replica) 라고 합니다.
  • 데이터베이스의 모든 쓰기는 모든 복제 서버에서 처리되어야 합니다. 이를 위한 해결책은 다음과 같습니다.
    • 리더 기반 복제(leader-based replication)
    • 능동(active)/수동(passive)
    • 마스터(master) 슬레이브(slave) 복제
  • 복제 서버 중 하나를 리더(leader, 마스터나 프라이머리(primary)) 로 지정합니다.
  • 다른 복제 서버는 팔로워(follower)(읽기 복제 서버(read replica), 슬레이브, 2차(secondary), 핫 대기(hot standby)) 라고 합니다.
  • 리더가 로컬 저장소에 새로운 데이터를 기록할 때마다 데이터 변경을 복제 로그(replication log)변경 스트림(change stream) 의 일부로 팔로워에게 전송합니다.
  • 이러한 복제 모드는 많은 관계형 데이터베이스, 몽고DB와 같은 비관계형 DB, 카프카 등의 분산 메시지 브로커에도 사용됩니다.

동기식 대 비동기식 복제#

  • 복제 시스템의 중요한 세부 사항은 복제가 동기식으로 발생하는지 비동기식으로 발생하는지 여부합니다.

동기식#

  • 다음의 예시는 동기식입니다. 동기식 복제의 장점은 팔로워가 리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장합니다. (다만, 이 경우는 비현실적 입니다.)
  • 현실적으로 동기식 복제를 사용하려면 팔로워 하나는 동기식, 그 밖에는 비동기식으로 하는 경우가 많습니다. 이러한 설정을 반동기식(semi-synchronous) 라고 합니다.

비동기식#

  • 보통 리더 기반 복제는 완전히 비동기식으로 구성합니다.
  • 리더가 잘못되었을 때 복구가 어렵고 쓰기에 지속성을 보장하지 않는다는 의미입니다.
  • 비동기식 설정은 모든 팔로워가 잘못되더라도 리더가 쓰기 처리를 계속 할 수 있는 장점이 있습니다.
  • 비동기식 복제는 내구성을 약화시키기 때문에 나쁜 트레이드오프로 보이나 팔로워가 많거나 분산 구조일 때는 많이 사용됩니다.

새로운 팔로워 설정#

  • 대부분의 신규 팔로워 설정은 중단시간 없이 수행할 수 있습니다.
    • (1) 가능하면 데이터를 잠그지 않고 리더의 데이터베이스 스냅숏을 일정 시점에 가져옵니다.
    • (2) 스냅숏을 새로운 팔로워 노드에 복사합니다.
    • (3) 스냅숏 이후 발생한 모든 데이터 변경을 요청합니다. (로그 데이터 이용)
    • (4) 데이터 변경의 미처리분(backlog)을 모두 처리했을 때 따라잡았다고 이야기하며 리더에 발생하는 데이터 변화를 처리할 수 있습니다.

노드 중단 처리#

시스템의 모든 노드는 장애나 유지보수로 인해 중단될 수 있습니다. 이는 큰 장점 중 하나이며 목표는 노드 중단의 영향을 최소화 하는 것이 목표입니다.

팔로워 장애: 따라잡기 복구#

  • 각 팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관하여 이후에 쉽게 복구합니다.

리더 장애: 장애 복구#

  • 리더의 장애를 처리하는 일은 까다롭습니다. 팔로워 중 하나를 새로운 리더로 승격해야 하고 클라이언트는 새로운 리더로 쓰기를 전송하기 위해 재설정이 필요하며 다른 팔로워는 새로운 리더로부터 데이터 변경을 소비하기 시작해야합니다. 이를 장애 복구 라고 합니다.
  • 자동 장애 복구는 다음과 같은 단계로 진행됩니다.
    • (1) 리더가 장애인지 판단
    • (2) 새로운 리더를 선택
    • (3) 새로운 리더 사용을 위해 시스템을 설정합니다.
  • 장애 복구 과정에서 여러 문제가 발생할 수 있습니다.
    • 비동기식 복제인 경우, 이전 리더의 쓰기를 일부 수신하지 못할 수가 있습니다.
    • 쓰기를 폐기하는 방법이 데이터베이스 외부의 다른 저장소 시스템이 데이터베이스 내용에 맞춰 조정되야 한다면 특히 위험합니다.
    • 특정 결함 시나리오에서 두 노드가 모두 자신이 리더라고 믿을 수 있습니다. (스플릿 브레인, split brain)
    • 타임아웃이 짧은 경우 불필요한 장애 복구가 있을 수 있습니다.
  • 이러한 문제로 인해 수동 장애 복구를 하는 경우도 많습니다.

복제 로그 구현#

구문 기반 복제#

  • 가장 간단한 사례로 리더는 모든 쓰기 요청(구문, statement)을 기록하고 쓰기를 실행합니다. 즉, SQL 구문을 파싱하고 실행하는 경우 입니다.

쓰기 전 로그 배송#

  • 일반적으로 모든 쓰기는 로그에 기록합니다.
    • 로그 구조화 저장소 엔진의 경우 로그 자체가 저장소의 주요 부분입니다. 로그 세그먼트는 작게 유지되고 백그아운드로 가비지 컬렉션을 합니다.
    • 개별 디스크 블록에 덮어쓰는 B 트리의 경우 모든 쓰기 전 로그(WAL) 에 쓰기 때문에 고장 이후 일관성 있는 상태로 색인을 복원할 수 있습니다.
  • 두 경우 모두 로그는 데이터베이스의 모든 쓰기를 포함하느 추가 전용(append-only) 바이트 열입니다.
  • PostgreSQL, Oracle 등에서 주로 사용됩니다.
  • 큰 단점은 로그가 제일 저수준의 데이터를 기술합니다. (즉, 데이터베이스 버전이 다른 경우 실행할 수 없습니다.)
    • 다만, 팔로워가 리더보다 새로운 소프트웨어 버전을 사용하게 설정하면 문제를 해결할 수도 있습니다.
    • 불일치가 허용되지 않는다면 업그레이드시마다 중단 시간이 필요합니다.

논리적(로우 기반) 로그 복제#

  • 복제 로그를 저장소 엔진 내부와 분리하기 위한 대안 하나는 복제와 저장소 엔진을 위해 다른 로그 형식을 사용하는 것이며 이를 논리적 로그(logical log) 라고 부릅니다.
    • 삽입된 로우의 로그는 모든 칼럼의 새로운 값을 포함합니다.
    • 삭제된 로우의 로그는 로우를 고유하게 식별하는데 필요한 정보를 포함해야합니다.
    • 갱신된 로우의 로그는 로우를 고유하게 식별하는데 필요하는 정보와 모든 칼럼의 새로운 값을 포함합니다.
  • 이러한 논리적 로그 형식은 외부 애플리케이션이 파싱하기 더 쉬우며 이 기술을 변경 데이터 캡처(change data capture) 라고 부릅니다.

트리거 기반 복제#

  • 지금까지 설명한 복제 접근 방식은 애플리케이션 코드의 사용 없이 데이터베이스 시스템에 의해 구현됩니다.
  • 조금 더 유연성이 필요한 상황에서는 복제의 기능을 애플리케이션 층으로 옮깁니다.
  • 오라클의 골든 게이트 같은 도구는 트리거나 스토어드 프로시저를 사용합니다.
  • 트리거는 사용자 정의 애플리케이션 코드를 등록할 수 있게 합니다. 이 애플리케이션 코드는 데이터베이스 시스템에서 데이터가 변경되면 자동으로 실행됩니다.
  • 일반적으로 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있습니다. 이 방식은 데이터베이스에 내장된 복제보다 버그나 제한 사항이 더 많이 발생하며 그럼에도 유연성에 장점이 있어 유리합니다.

복제 지연 문제#

  • 노드 내결함성을 갖추려는 단 한가지 이유는 복제가 필요하기 때문입니다.
  • 리더 기반 복제는 모든 쓰기가 단일 노드를 거쳐야 하지만 읽기 전용 질의는 어떤 복제 서버에서도 가능합니다.
  • 이러한 읽기 확장(read-scaling) 아키텍처에서는 간단히 팔로워를 더 추가함으로써 읽기 전용 요청을 처리하기 위한 용량을 늘릴 수 있습니다.
  • 애플리케이션이 비동기 팔로워에서 덴이터를 읽을 때 팔로워가 뒤처진다면 지난 정보를 볼 수도 있습니다. 이때는 데이터베이스에 쓰기를 멈추고 잠시동안 기다리면 팔로워는 따라잡게 되고 리더와 일치하게 되며 이런 효과를 최종적 일관성이라고 합니다.
  • 애플리케이션에서 지연이 매우 크면 불일치는 이론적인 문제가 아닌 실제 문제가 됩니다.

아래는 복제 지연이 발생할 때 발생하는 세 가지 사례입니다.

자신이 쓴 내용 읽기#

  • 새로운 데이터가 제출되면 리더에게 전송해야 하지만 사용자가 데이터를 볼 때는 팔로워에서 읽을 수 있습니다. 특히 데이터를 자주 읽고 적게 쓸때 유리합니다.
  • 비동기식 복제는 사용자가 쓰기를 수행한 직후 데이터를 본다면 새로운 데이터는 아직 복제 서버에 반영되지 않았을 수 있습니다.
  • 이런 경우, 쓰기 후 읽기 일관성이 필요합니다. 다양한 기법이 존재합니다.
    • 수정 내용을 읽을 때는 리더에서 읽기
    • 일정 시간은 리더에서 모든 읽기, 복제 지연을 모니터링해 리더보다 일정시간 보다 이상 늦은 팔로워에 대해 질의를 금지합니다.
    • 클라이언트는 가장 최근 쓰기의 타임스탬프를 기록할 수 있으므로 갱신을 반영하기 전까지 질의를 대리합니다.
    • 복제 서버가 여러 데이터센터에 분산되어 있다면 리더가 제공해야 하는 모든 요청은 리더가 포함된 데이터센터로 라우팅돼야합니다.
  • 동일한 사용자가 여러 디바이스로 서비스를 접근할 때 또 다른 문제가 발생합니다. 이때는 디바이스 간(cross-device) 쓰기 후 읽기 일관성이 제공돼야 합니다.
    • 한 디바이스가 다른 디바이스의 갱신을 모르므로 메타데이터는 중앙집중식으로 관리합니다.
    • 복제 서버가 여러 데이터센터 간에 분산된 경우 동일 데이터센터로 라우팅된다는 보장이 없으므로 필요하다면 동일한 데이터센터로 라우팅합니다.

단조 읽기#

비동기식 팔로워에서 읽을 때 발생할 수 있는 두 번째 이상 현상은 사용자가 시간이 거꾸로 흐르는 현상을 볼 수 있습니다.

시간 역행

단조 읽기(monotonic read)는 이런 종류의 이상 현상이 발생하지 않음을 보장합니다.

  • 단조 읽기는 강한 일관성보다는 덜한 보장이지만 최종적 일관성보다는 강한 보장입니다. 즉, 데이터를 읽을 때 이전 값을 볼 수는 있으나 시간 역행은 불가능합니다.
  • 이를 구현하는 한 방법은 읽기가 항상 동일한 복세 서버에서 수행되게 하는 것입니다.

일관된 순서로 읽기#

세번째 복제 지연 이상 현상은 인과성의 위반 우려입니다.

인과성의 위반

  • 이런 경우, 관찰자에게는 질문 전 대답으로 보입니다.

이런 종류의 이상 현상을 방지하려면 일관된 순서로 읽기(Consistent Prefix Read) 같은 또 다른 유형의 보장이 필요합니다.

  • 일관된 순서는 읽기가 일련의 쓰기가 특정 순서로 발생한다면 쓰기를 읽는 모든 사용자는 같은 순서로 쓰여진 내용을 보게 됨을 보장합니다.
  • 파티셔닝된 데이터베이스에서 발생하는 특징적인 문제 중 하나입니다.
  • 한 가지 해결책은 서로 인과성이 있는 쓰기가 동일한 파티션에 기록되게끔 하는 방법입니다. 다만 효율적이지 않는 경우가 존재합니다.

복제 지연을 위한 해결책#

  • 최종적 일관성시스템으로 작업할 때 복제 지연이 몇 분이나 몇 시간으로 증가한다면 애플리케이션이 어떻게 동작할지 생각해 볼 가치가 있습니다.
  • 애플리케이션이 기본 데이터베이스보다 강력한 보장을 제공하는 방법이 있습니다. (다만 이를 애플리케이션 코드에서 처리하기는 복잡해서 잘못되기 쉽습니다.)
  • 애플리케이션 개발자가 이러한 복제 문제를 걱정하지 않고 "올바른 작업 수행"을 위해 항상 데이터베이스를 신뢰할 수 있다면 훨씬 좋습니다. 이가 트랜잭션이 있는 이유입니다.
  • 오랫동안 단일 노드 트랜잭션은 존재했으나 분산 데이터베이스로 전환하는 과정에서 많은 시스템이 트랜잭션을 포기했습니다.

다중 리더 복제#

  • 앞에서는 단일 리더를 사용한 복제 아키텍처만 고려했으며 이는 일반적입니다.
  • 그러나 가장 큰 단점은, 어떤 리더에 어떤 이유로 연결할 수 없다면 데이터베이스에 쓰기가 불가능합니다.
  • 리더 기반 복제 모델은 쓰기를 허용하는 노드를 하나 이상 둠으로써 확장할 수 있습니다.
  • 쓰기 처리를 하는 각 노드는 데이터 변경을 다른 모든 노드에 전달하며 이런 방식을 다중 리더 설정(혹은 마스터 마스터, 액티브/액티브 복제)라고 합니다. 각 리더는 동시에 다른 리더의 팔로워 역할도 합니다.

다중 리더 복제의 사용 사례#

  • 단일 데이터센터 내에 다중 리더 설정을 사용하는 설정은 이로 인해 추가된 복잡도에 비해 이점이 크지 않기 때문에 적절하지 않습니다.

다중 데이터센터 운영#

다중 데이터센터

  • 다중 리더 설정에서는 각 데이터센터마다 리더가 있을 수 있습니다.
  • 각 데이터센터 내에서는 보통의 리더 팔로워 복제를 사용하고 데이터센터 간에는 각 데이터 센터의 리더가 다른 데이터센터의 리더에게 변경 사항을 복제합니다.
-단일 리더 설정다중 리더 설정
성능모든 쓰기는 리더가 있는 데이터센터로 이동해야함, 쓰기 지연 발생모든 쓰기는 로컬 데이터센터에서 처리후 비동기 방식으로 다른 데이터센터 복제, 성능이 좋음
데이터센터 중단 내성다른 데이터센터의 팔로워를 리더로 승진각 데이터센터는 독립적이며, 온라인으로 돌아올 시 복제를 따라잡습니다
네트워크 문제 내성데이터센터 내 연결의 쓰기는 동기식이므로 연결 문제에 민감일시적인 네트워크 중단이라도 쓰기 처리가 진행됩니다.
  • 일부 데이터 베이스는 기본적으로 다중 리더 설정을 제공합니다.
  • 다중 리더 복제에는 분명 이점이 있으나 큰 단점으로 동일한 데이터를 다른 두 개의 데이터센터에서 동시에 변경할 수 있습니다.

오프라인 작업을 하는 클라이언트#

  • 대표적인 예시로 휴대폰의 캘린더앱이며 언제든 일정을 볼 수 있어야하고 (읽기 요청) 언제라도 새로운 일정을 생성할 수 있어합니다. (쓰기 요청) 이 후 정상이 되면 다른 디바이스와 동기화되어야합니다.
  • 아키텍처 개념에서 이러한 설정은 데이터센터 간 다중 리더 복제와 동일합니다.

협업 편집#

  • 여러 사람이 문서를 편집할 수 있는 애플리케이션을 실시간 협업 편집 애플리케이션이라고 합니다. (ex. etherpad, google docs)
  • 편집 충돌이 없음을 보장하려면 애플리케이션은 사용자가 편집하기 전에 문서의 잠금을 얻어야 합니다.
  • 하지만 더 빠른 협업을 위해 여러 사용자가 동시에 편집할 수 있지만 충돌 해소가 필요한 경우를 포함해 다중 리더 복제에서 발생하는 모든 문제를 야기합니다.

쓰기 충돌 다루기#

쓰기 충돌

동기 대 비동기 충돌 감지#

  • 단일 리더 데이터베이스에서 첫 번째 쓰기가 완료될 때까지 두번째 쓰기를 차단해서 기다리거나 트랜잭션을 종료해서 사용자가 쓰기를 재시도 하게 합니다.
  • 다중 리더 설정에서 두 쓰기는 모두 성공하며 충돌은 이후 특정 시점에서 비동기로만 감지합니다. 이때 사용자에게 충돌을 해소하게 끔 요청하면 너무 늦을 수 있습니다.

충돌 회피#

  • 제일 간단한 전략은 충돌을 피하는 것입니다.
  • 특정 레코드의 모든 쓰기가 동일한 리더를 거치도록 애플리케이션이 보장한다면 충돌은 발생하지 않습니다. (자주 권장됩니다.)
    • 즉, 한 사용자의 관점에서는 단일 리더로 보이게 됩니다. (지역적인 라우팅 전략)
  • 때로는 한 데이터센터가 고장나서 트래픽을 다른 데이터센터로 다시 라우팅해야하거나 사용자가 다른 지역으로 이동해 현재는 다른 데이터센터가 가깝다면 레코드를 위해 지정된 리더가 변경을 원하는 상황에서는 충돌 회피가 실패합니다.

일관된 상태 수렴#

  • 단일 리더 데이터베이스는 순차적인 순서로 쓰기를 적용하나 다중 리더 설정에는 쓰기 순서가 정해지지 않아 최종값이 명확하지 않습니다.
  • 따라서 데이터베이스는 수렴(convergent) 방식으로 충돌을 해소해야합니다.
    • 각 쓰기에 고유 ID를 주고 가장 높은 ID를 가진 쓰기를 선택합니다.
    • 각 복제 서버에 고유 ID를 주고 우선순위를 줍니다.
    • 어떻게든 값을 병합합니다. (Ex. B + C = B/C)
    • 명시적 데이터 구조에 충돌을 기록해 모든 정보를 보존하고, 사용자에게 충돌을 보여주어 해결하도록 합니다.

사용자 정의 충돌 해소 로직#

  • 충돌을 해소하는 가장 적합한 방법은 애플리케이션에 따라 다릅니다.
    • 쓰기 수행 중 : 복제된 변경 사항 로그에서 데이터베이스 시스템이 충돌을 감지하자마자 충돌 핸들러를 호출합니다.
    • 읽기 수행 중 : 충돌을 감지하면 모든 충돌 쓰기를 저장합니다.
  • 충돌 해소는 보통 전체 트랜잭션이 아니라 개별 로우나 문서 수준에서 적용됩니다. 즉, 원자적으로 여러 다른 쓰기를 수행하는 트랜잭션이라면 각 쓰기는 충돌 해소를 위해 여전히 별도로 간주됩니다.

자동 충돌 해소

  • 대표적인 예시로 아마존 장바구니 충돌 해소 로직은 얼마 동안 추가도니 상품을 보존하나 삭제한 상품은 보존하지 않습니다. (즉, 삭제해도 가끔 장바구니에서 다시 해당 상품이 보이는 경우가 있습니다.)
    • 충돌 없는 복제 데이터타입 : set, map, 정렬 목록
    • 병합 가능한 영속 데이터 구조(mergeable persistent data structure)는 깃과 비슷하게 히스토리 추적후 삼중 병합 합수를 사용합니다.
    • 운영 변환(operational transformation)은 이더패드나 구글 독스와 비슷합니다.

충돌은 무엇인가?#

  • 어떤 종류의 충돌은 감지하기 어렵습니다.
    • 대표적인 예시로 회의실 예약 시스템이 있습니다. (즉, 에학 허용하기전에 가능하더라도 두 예약이 다른 리더에서 이뤄지면 충돌이 가능합니다.)
  • 관련된 답은 없으나 가장 적합한 방식으로 진행합니다.

다중 리더 복제 토폴로지#

  • 복제 토폴로지는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명합니다.
  • 리더가 둘 이상이라면 다양한 토폴로지가 가능합니다. (원형, 별, 전체 연결)
  • 가장 일반적인 토폴로지는 전체 연결(all-to-all) 입니다. (각자 쓰기를 다른 모든 리더에서 전송합니다.)
  • MySQL의 경우 기본적으로 원형 토폴로지(circular topology) ∂만 제공합니다.
  • 별 모양 토폴로지도 많이 쓰며, 트리로 일반화 할 수 있습니다.

이에 따라 여러 장단점을 가집니다.

  • 원형과 별의 경우, 모든 복제 서버에 도달하기 전에 여러 노드를 거쳐야 함으로 각 노드에 고유 식별자가 있고 이미 처리한 경우에는 무시합니다. (메시지 흐름에 장애가 발생할 수 있다는 단점이 존재합니다.)
  • 전체 연결 토폴로지의 경우, 일부 네트워크 연결이 다른 연결보다 빠르다면 일부 복제 메시지가 다른 메시지를 추월할 수 도 있습니다.

이러한 문제를 해결하기 위해 버전 벡터(version vector) 라는 기법을 사용할 수 있으나 많은 다중 리더 복제 시스템에서는 제대로 구현되지 않았습니다.


리더 없는 복제#

  • 일부 데이터 저장소 시스템은 리더의 개념을 버리고 모든 복제 서버가 클라이언트로부터 쓰기를 직접 받을 수 있게 허용하는 접근 방식을 사용합니다.
  • 이 개념은 관계형 데이터베이스가 우세한 시스템에는 대부분 잊혀졌으며 아마존이 내부 다이나모(Dynamo) 시스템에서 사용한 후 다시 데이터베이스용 아키텍처로 유행했습니다.

Amazon DynamoDB Architecture

  • 일부 리더 없는 복제 구현에서는 클라이언트가 여러 복제 서버에 쓰기를 직접 전송하는 반면 코디네이터 노드(coordinator node)가 클라이언트를 대신해 이를 수행하기도 합니다.
  • 그러나 리더 데이터베이스와 달리 코디네이터 노드는 특정 순서로 쓰기를 수행하지 않습니다.

노드가 다운됐을 때 데이터베이스에 쓰기#

  • 리더가 없는 설정에서는 장애 복구가 필요하지 않습니다.
  • 죽은 노드의 경우, 데이터가 오래된(outdated) 값을 얻을 수 있습니다.
  • 이 문제를 해결하기 위해 클라이언트가 데이터를 읽을 때 읽기 요청을 병렬로 여러 노드에 전송합니다. 그러면 클라이언트는 여러 노드에서 다른 응답을 받을 수 있고 이때는 최신과 버전 숫자를 통해 최신 값을 결정합니다.

읽기 복구와 안티 엔트로피#

  • 모든 데이터가 모든 복제 서버에 복사된 것을 보장해야합니다. 이를 위해 두가지 메커니즘을 주로 사용합니다.
    • 읽기 복구 : 클라이언트가 여러 노드에서 병렬로 읽기를 수행할 때 오래된 응답을 인식가능합니다. 따라서 해당 복제 서버에 새로운 값을 다시 기록합니다. (값을 자주 읽을 때 좋습니다.)
    • 안티 엔트로피 처리 : 일부 데이터스토어는 백그라우드 프로세스를 두고 복제 서버 간 데이터 차이를 지속적으로 찾아 누락덴 데잍처를 하나의 복제 서버에서 다른 서버로 복사합니다.
  • 거의 읽지 않는 경우는 일부 복제본에서 누락되는 경우도 있습니다.

읽기와 쓰기를 위한 정족수#

  • 모든 성공한 쓰기가 세개의 복제 서버 중 두개의 복제 서버에 존재한다는 것을 보장한다면 하나의 서버가 오래됨을 의미합니다.
  • 이를 일반화하면 n개의 복제 서버가 있을 때 모든 쓰기는 w개의 노드에서 성공해야 쓰기가 확정됩니다. 따라서 읽기는 최소한 r개의 노드에 질의를 해야합니다.
  • 일반적으로 n개를 홀 수로 하고, w = r = (n + 1) / 2 등으로 설정합니다. 읽기가 많은 경우, w = n, r = 1 로 선택하는 것도 좋은 전략입니다.

정족수 일관성의 한계#

n : 복제 서버 수, w : 필요 성공 노드, r : 최소 질의 노드

  • w + r > n : 일반적으로 모든 읽기는 키의 최신 값을 반환할 것을 기대
  • r, w > n/2 : 일반적인 경우, 다른 정족수 할당이 가능하기 때문에 분산 알고리즘 설계에서 유연합니다.
  • w + r <= n : 읽기와 쓰기를 계속 n개의 노드로 전송하지만 성공에 필요한 성공 응답 수가 더 적습니다.
  • w, r 이 적은 경우 : 오래된 값을 읽을 확률이 높습니다.

위의 내용을 통해 확률을 조정할 수는 있으나 절대적으로 보장할 수 없습니다.

최신성 모니터링#

  • 운영 관점에서는 데이터베이스가 최신 결과를 반환하는 것이 중요합니다. 따라서 이를 모니터링이 필요하지만 오래된 정보에 대한 제한이 없어서 모니터링이 어렵습니다.

느슨한 정족수와 암시된 핸드오프#

  • 적절히 설정된 정족수가 있느 데이터베이스는 장애 복구 없이 개별 노드 장애를 용인합니다.
  • 위의 설명대로는 정족수는 내결함성이 없습니다. 네트워크 중단으로 다수의 데이터베이스 노드와 클라이언트는 쉽게 연결이 끈헝질 수 있습니다.
  • 노드가 n개 이상인 대규모 클러스터에서는 클라이언트는 네트워크 장애 상황에서 일부 데이터베이스 노드(특정 값을 위한 정족수 구성에 들어가지 않는 노드)에 연결될 가능성이 있습니다. 이 경우 데이터베이스 설계자는 트레이드 오프에 직면합니다.
    • w나 r 노드 정족수를 만족하지 않는 모든 요청에 오류를 반환하는 게 맞을까?
    • 혹은 쓰기를 받아들이고 값이 보통 저장되는 n개 노드에 속하지는 않지만 연결할 수 있는 노드에 기록할지 (느슨한 정족수)
  • 네트워크 장애 상황이 해제되면 한 노드가 다른 노드를 위해 일시적으로 수용한 모든 쓰기를 해당 홈 노드로 전송합니다. 이 방식을 암시도니 핸드오프라 부릅니다.
  • 느슨한 정족수는 쓰기 가용성을 높이는 데 특히 유용합니다.

다중 데이터센터 운영#

  • 리더 없는 복제도 동시 쓰기 충돌, 네트워크 중단, 지연 시간 급증을 허용하기 때문에 다중 데이터센터 운영에 적합합니다.

동시 쓰기 감지#

  • 다이나모 스타일은 여러 클라이언트가 동시에 같은 키에 쓰는 것을 허용하기 때문에 엄격한 정족수를 사용하더라도 충돌이 발생합니다.

동시 쓰기

최종 쓰기 승리(동시 쓰기 버리기)#

  • 최종적으로 값을 수렴하기 위한 접근 방식 중 하나는 "예전" 값을 버리고 가장 "최신" 값을 덮는 방법입니다.
  • "최신"이란 먼저가 확신하지 않기 때문에 사실 상 동시라는 의미가 맞고, 타임스탬프를 통해 임의로 최신이라고 정정하는 것입니다.

"이전 발생" 관계와 동시성#

  • 두 가지 작업이 동시적에 수행했는 지 알수 있는 방법은 다음과 같습니다.
  • 예를 들어, 작업 B가 A에 대해서 알거나 A에 의존성이 있으면 작업 A는 작업 B의 이전 발생(happens-before) 입니다.
  • 서로 다른 작업인 경우에 단순히 동시 작업이라고 합니다.

동시성, 시각, 상대성

동시성을 정의할 때 정확한 시간은 중요하지 않습니다. 두 작업이 발생한 시각보다 서로 알지못하면 단순히 두 작업이 동시에 수행되었다고 합니다.

이전 발생 관계 파악하기#

  • 인과관계를 통해 인과성 도표를 설정합니다.
  • 쓰기가 이전 읽기의 버전 번호를 포함하면 쓰기가 수행되기 이전 상태를 알 수 있습니다.

동시에 쓴 값 병합#

  • 클라이언트가 추가적으로 작업을 수행해야 합니다.
  • 여러 작업이 동시에 발생하면 클라이언트는 동시에 쓴 값을 합쳐 정리해야합니다. (리악에서는 이러한 동시 값을 형제, sibling이라고 합니다.)

버전 벡터#

  • 앞에서의 단일 버전 번호는 다중 복제본의 동시 쓰기를 받아들일 때는 충분하지 않습니다. 키당 버전 번호뿐만 아니라 복제본당 버전 번호를 사용해야 합니다.
  • 모든 복제본의 버전 번호 모음을 버전 벡터(version vector) 라고 부릅니다.
  • 버전 벡터 구조는 하나의 복제본을 읽은 다음 이어 다른 복제본에 다시 쓰는 작업이 안전함을 보장합니다.

정리#

복제는 다양한 용도로 사용가능합니다.

  • 고가용성 : 한 장비가 다운될 때도 시스템이 계속 동작
  • 연결이 끊긴 작업 : 네트워크 중단이 있을 때도 애플리케이션이 계속 동작할 수 있게 합니다.
  • 지연 시간 : 지리적으로 사용자에게 가까이 데이터를 배치해 사용자가 더 빠르게 작업할 수 있게 합니다.
  • 확장성 : 복제본에서 읽기를 수행해 단일 장비에서 다룰 수 있는 양보다 많은 양의 읽기 작업을 처리할 수 있습니다.

복제에 대한 세 가지 주요 접근 방식은 아래와 같습니다.

  • 단일 리더 복제
    • 클라이언트는 모든 쓰기를 단일 노드(리더)로 전송하고 리더는 데이터 변경 이벤트 스트림을 다른 복제 서버로 전송합니다.
    • 읽기는 모든 복제 서버가 수행할 수 있지만 팔로워의 읽기는 오래된 값일 수도 있습니다.
    • 이해하기 쉽고 충돌 해소에 대한 우려가 없어서 널리 사용됩니다.
  • 다중 리더 복제
    • 클라이언트는 각 쓰기를 여러 리더 노드 중 쓰기를 받아들일 수 있는 노드로 전송합니다.
    • 리더는 데이터 변경 이벤트 스트림을 다른 리더와 모든 팔로워 노드로 전송합니다.
    • 결함 노드, 네트워크 중단, 지연 시간 급증이 있는 상황에서 더욱 견고합니다.
  • 리더 없는 복제
    • 클라이언트는 각 쓰기를 여러 노드로 전송합니다. 클라이언트는 오래된 데이터를 감지하고 이를 바로잡기 위해 병렬로 여러 노드에서 읽습니다.

복제는 동기와 비동기로 이뤄집니다. 복제 지연으로 인해 발생하는 여러 문제가 있고 이를 해결하기 위해 일부 일관성 모델이 있습니다.

  • 쓰기 후 읽기 일관성
    • 사용자는 자신이 제출한 데이터를 항상 볼 수 있어야합니다.
  • 단조 읽기
    • 사용자가 어떤 시점에 데이터를 본 후에는 예전 시점의 데이터를 나중에 볼 수 없습니다.
  • 일돤된 순서로 읽기
    • 사용자는 인과성이 있는 상태의 데이터를 봐야합니다.

다중 리더 복제와 리더 없는 복제 접근 방식에 내재된 동시성 문제도 있습니다.

Last updated on