개요

  • 이 문서는 [[Designing-Data-Intensive-Applications]]책의 5장을 공부하며 메모한 것입니다.
  • 이 문서는 메모일 뿐이니 자세한 내용은 교재를 참고해야 합니다.

복제

네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지하는 것.

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

이번 장에서 알아볼 세 가지 복제 알고리즘

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

리더와 팔로워(Leaders and Followers)

  • 복제 서버(replica): DB의 복사본을 저장하는 각 노드.
  • 리더 기반 복제(leader-based replication)
    • active/passive 복제라고도 한다.
    • master/slave 복제라고도 한다.

리더 기반 복제를 수행하는 방법은 다음과 같다.

  • 복제 서버 중 하나를 리더(leader, 또는 master, primary)로 정한다.
    • 다른 복제 서버는 팔로워(follower, read replica, slave, secondary, hot standby)로 정한다.
  • 클라이언트가 DB에 쓰기 요청을 리더에게 보낸다.
  • 리더는 로컬 저장소에 신규 데이터를 기록한다.
  • 리더가 신규 데이터를 기록할 때마다 변경 사항을 복제 로그(replication log)나 변경 스트림(change stream)의 일부로 팔로워에게 전송한다.
  • 각 팔로워는 리더로부터 로그를 받아, 리더가 처리한 것과 동일한 순서로 모든 쓰기를 적용한다.

읽기는 리더/팔로워 아무에게나 질의할 수 있다.

그러나 쓰기는 리더에게만 허용한다.

동기식 대 비동기식 복제

동기식 복제의 장점

  • 팔로워와 리더가 일관성 있게 최신 데이터 복사본을 가지는 것을 보장한다.
  • 리더가 작동하지 않아도 데이터는 팔로워에서 계속 사용할 수 있음.

동기식 복제의 단점

  • 팔로워가 응답이 없으면 쓰기가 처리되지 않는다.
    • 리더는 모든 쓰기를 차단(block)하고, 복제 서버를 다시 사용할 수 있을 때까지 기다려야 한다.

따라서 모든 팔로워를 동기식으로 사용하는 것은 곤란하다.

  • 일반적으로 팔로워 하나는 동기식으로 하고, 나머지는 비동기식으로 한다.
  • 동기식 팔로워가 느려지거나 사용할 수 없게 되면 비동기식 팔로워 중 하나가 동기식이 된다.
    • 이렇게 하면 적어도 2개의 노드에 데이터의 최신 복사본이 있는 것을 보장할 수 있다.
    • 이런 설정을 반동기식(semi-synchronous)라 부른다.

새로운 팔로워 설정

새로운 팔로워가 리더의 데이터 복제본을 정확히 갖고 있는지 어떻게 보장하는가?

  • DB의 쓰기를 잠그고 복제한다면, 일관성은 획득하나, 고가용성은 희생하게 된다.

중단시간 없이 팔로워를 설정하려면 다음과 같이 한다.

  • DB를 잠그지 않고, 리더의 DB 스냅샷을 가져온다.
  • 스냅샷을 새로운 팔로워 노드에 복사한다.
  • 팔로워를 리더에 연결하여 스냅샷 이후 발생한 모든 데이터 변경을 요청한다.
  • 팔로워가 스냅샷 이후 데이터 변경을 모두 처리하면 "따라잡았다(caught up)"고 한다.

노드 중단 처리(Handling Node Outages)

중단 시간 없이 개별 노드를 재부팅할 수 있다는 점은 운영과 유지보수에 큰 장점.

개별 노드의 장애에도 전체 시스템이 동작하게끔 유지하고 노드 중단의 영향을 최소화하는 것이 목표.

리더 기반 복제에서 고가용성은 어떻게 달성하는가?

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

팔로워 복구는 쉽다.

  1. 결함 발생 전에 처리한 마지막 트랜잭션을 알아낸다.
  2. 리더에 연결해 팔로워 연결이 끊어진 동안 발생한 데이터 변경을 모두 요청한다.
  3. 변경이 모두 적용되면 리더를 따라잡게 된다.

리더 장애 : 장애 복구

리더 장애 처리는 어렵다.

자동 장애 복구 기능이 있더라도, 수동으로 장애 복구를 하는 쪽을 선호하는 경우도 많다.

  • 장애 복구(failover) 과정
    • 팔로워 중 하나를 새로운 리더로 삼아야 한다.
    • 클라이언트는 새로운 리더로 쓰기를 전송해야 하므로 재설정이 필요.
    • 다른 팔로워는 새로운 리더를 바라봐야 한다.

복제 로그 구현

리더 기반 복제의 동작을 알아본다.

구문 기반 복제

  • 리더는 모든 쓰기 요청(statement, 구문)을 기록하고,
  • 쓰기를 실행한 다음,
  • 구문 로그를 팔로워에게 전송한다.

RDB라면

  • 모든 INSERT, UPDATE, DELETE 구문을 팔로워에게 전달하고,
  • 팔로워는 SQL 구문을 파싱하고 실행한다.

이 방법의 문제점들

  • 구문에서 NOW(), RAND() 같은 비결정적 함수를 호출하는 경우.
  • auto increment 칼럼을 쓰거나 DB의 데이터에 의존하는 구문이라면 각 복제 서버에서 정확히 같은 순서로 실행해야 함.
  • 부수 효과를 가진 구문(트리거, 스토어드 프로시저, 사용자 정의 함수 등)으로, 각 복제 서버에서 다른 부수 효과가 발생할 수 있음.

문제점의 대안은

  • 리더는 구문을 기록할 때, 모든 비결정적 함수 호출을 고정 값을 반환하게끔 한다.

쓰기 전 로그 배송

완전히 동일한 로그를 사용해 다른 노드에서 복제 서버를 구축할 수 있다.

  • 리더는 디스크에 로그를 기록하고, 팔로워에게 네트워크로 로그를 전송한다.
  • 팔로워가 전송받은 로그를 처리하면 리더와 동일한 데이터 구조의 복제본이 만들어짐.

주의점

  • 로그가 제일 저수준의 데이터를 기술하고 있으므로,
    • 저장소 엔진 의존성이 생긴다.
      • 리더와 팔로워의 DB 버전을 다르게 하면 안됨.
    • 버전 업데이트시, 팔로워를 먼저 업데이트하고, 리더를 나중에 업데이트.

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

복제 로그를 저장소 엔진과 분리하기 위한 대안

비 의존적인 로그 형식(logical log, 논리적 로그)을 사용한다.

  • 삽입된 로우의 로그는 모든 칼럼의 새로운 값을 포함한다.
  • 삭제된 로우의 로그는 로우를 고유하게 식별하는 데 필요한 정보를 포함한다.
  • 갱신된 로우의 로그는 로우를 고유하게 식별하는 데 필요한 정보와 모든 칼럼의 새로운 값을 포함한다.

트리거 기반 복제

  • 트리거는 애플리케이션 코드를 등록할 수 있게 한다.
    • 데이터베이스 시스템에서 데이터가 변경되면(쓰기 트랜잭션) 자동으로 실행된다.
  • 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있다.

복제 지연 문제

읽기 확장(read-scaling)

  • 대부분이 읽고 요청이고 쓰기 비율이 작으면 많은 팔로워를 만들어 읽기 요청을 분산.
  • 비동기식 복제에서만 동작한다.

최종적 일관성

  • 팔로워가 리더에 비해 뒤쳐진 경우(복제 지연) 불일치가 발생한다.
  • 최종적 일관성 : 잠시 기다리면 팔로워가 결국 따라잡아 리더와 일치하게 된다.

자신이 쓴 내용 읽기

  • 복제 지연이 일어났을 때
    • 사용자가 쓰기를 수행하고,
    • 곧바로 사용자가 데이터를 확인하면,
    • 팔로워에 아직 적용이 안 되어 데이터가 유실된 것으로 생각할 수 있다.

위와 같은 상황에서는 "쓰기 후 일관성(read-after-write consistency)"이 필요하다.

  • 사용자가 페이지를 재로딩했을 때, 자신이 제출한 모든 갱신을 볼 수 있음을 보장하는 기능.
  • 다른 사용자에 대해서는 보장하지 않는다.

쓰기 후 일관성 구현 방법

  • 사용자가 수정한 내용을 읽을 때는 리더에서 읽는다. 그 외에는 팔로워에서 읽는다.
    • 예: SNS에서 사용자 프로필 정보는 항상 리더에서만 읽고, 다른 사용자는 팔로워에서 읽는다.
  • 마지막 갱신 후 1분 동안은 리더에서 모든 읽기를 수행한다.
    • 복제 지연을 모니터링해 리더보다 1분 이상 늦은 모든 팔로워에 대한 질의를 금지하는 방법.
  • 복제 서버가 따라잡지 못했다면, 다른 복제 서버가 읽기를 처리한다.
    • 또는 따라잡을 때까지 질의를 대기시킨다.
  • 한 사용자가 여러 디바이스를 사용하는 경우, 디바이스 간 쓰기 후 읽기 일관성(cross-device read-after-write consistency)가 제공되어야 한다.

단조 읽기(Monotonic Reads)

비동기식 팔로워 방식에서 읽을 때, 사용자가 "시간이 거꾸로 흐르는 현상"을 목격할 수 있음.

  • 단조 읽기(monotonic read)는 이런 종류의 이상 현상의 방지를 보장한다.
  • 단조 읽기는 강한 일관성보다는 덜한 보장이지만, 최종적 일관성보다는 강한 보장이다.
    • 즉, 새로운 데이터를 읽은 후에는 예전 데이터를 읽지 않는다.

단조 읽기를 구현하는 방법

  • 각 사용자의 읽기가 항상 동일한 복제 서버에서 수행되게끔 한다.
    • 다른 사용자는 다른 복제서버에서 읽는다.
    • 예를 들어, 사용자 ID의 해시값을 기반으로 복제 서버를 선택한다.

일관된 순서로 읽기(Consistent Prefix Reads)

일련의 쓰기가 특정 순서로 발생한다면 이 쓰기를 읽는 모든 사용자는 같은 순서로 쓰여진 내용을 보게 됨을 보장.

이 문제는 뒤에서 따로 다룬다.

복제 지연을 위한 해결책

복제 지연이 몇 분, 몇 시간 정도로 증가한다면?

복제가 비동기식으로 동작하지만 동기식으로 동작하는 척 하는 것이 문제 해결 방안.

  • 그러나 애플리케이션 코드에서는 이 문제를 다루기엔 어렵다.
  • 트랜잭션 사용.
    • 트랜잭션은 애플리케이션이 더 단순해지기 위해 DB가 더 강력한 보장을 제공하는 방법.

다중 리더 복제(Multi-Leader Replication)

지금까지 다룬 싱글 리더 복제에는 다음과 같은 문제점이 있다.

  • 리더가 하나만 있고, 모든 쓰기는 리더를 거쳐야 한다.
  • 리더에 연결할 수 없는 상태라면 DB에 쓰기를 할 수 없다.

해결책

  • 다중 리더 설정 : 쓰기를 허용하는 노드를 하나 이상 두는 것으로 확장할 수 있다.
    • 각 리더는 동시에 다른 리더의 팔로워 역할도 한다.

다중 리더 복제의 사용 사례

  • 다중 데이터센터 운영
    • 다중 리더 설정에서는 각 데이터센터마다 리더가 있을 수 있다.
    • 각 데이터 센터 내에는 보통의 리더-팔로워 복제를 사용.
    • 데이터 센터 간에는 각 데이터 센터의 리더가 다른 데이터 센터의 리더에게 변경 사항을 복제한다.
  단일 리더 설정 다중 리더 설정
성능 모든 쓰기는 인터넷을 통해 리더가 있는 데이터센터로 이동.(지연 시간 높음) 모든 쓰기는 로컬 데이터센터에서 처리한 다음, 비동기 방식으로 다른 데이터센터에 복제한다.(네트워크 지연은 사용자에게 숨겨짐)
데이터센터 중단 내성 리더가 있는 데이터센터가 고장나면 다른 데이터센터의 팔로워를 리더로 승진. 다른 데이터센터와 독립적으로 동작하고, 고장난 데이터센터가 온라인으로 돌아왔을 때 복제를 따라잡는다.
네트워크 문제 내성 데이터센터 내 연결의 쓰기는 동기식이라 네트워크 연결 문제에 매우 민감. 비동기 복제를 사용하므로 네트워크 문제에 잘 견딘다. (일시적인 네트워크 중단에도 쓰기 처리는 진행되기 때문)

다중 리더 복제의 큰 단점

  • 동일한 데이터를 다른 두 개의 데이터 센터에서 동시에 변경할 수 있다.
    • 이런 쓰기 충돌 문제는 나중에 다룬다…
  • 미묘한 설정상의 실수나 다른 DB와의 문제가 발생할 수 있음.

쓰기 충돌 다루기

다중 리더 복제에서 발생하는 가장 큰 문제.

다음과 같은 방법들로 충돌 문제를 해결한다.

  • 충돌 감지
  • 충돌 회피(conflict avoidance)
  • 일관된 상태 수렴(converging toward a consistent state)

등등.

다중 리더 복제 토폴로지(Multi-Leader Replication Topologies)

복제 토폴로지(replication topology)는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명한다.

  • 원형 토폴로지
  • 별 모양 토폴로지
  • 전체 연결 토폴로지

리더 없는 복제

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

복제 서버 중 하나를 사용할 수 없는 상황에서

  • 리더 기반 설정에서 쓰기 처리를 계속하려면 장애 복구를 실행해야 한다.
  • 리더 없는 설정에서는 장애 복구가 필요하지 않다.

문제의 노드가 다시 온라인 상태가 되었을 때, 오래된 값을 얻는 것을 방지하려면

  • 클라이언트가 DB에서 읽을 때 하나의 복제 서버로 요청을 보내지 않고,
    • 읽기 요청을 병렬로 여러 노드로 전송한다.
    • 여러 노드에서 응답을 받은 다음, 버전을 비교해 가장 최신 내용을 보여준다.

정족수 일관성의 한계

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

동시 쓰기 감지

  • [[Designing-Data-Intensive-Applications]]