개요
복제란?
- 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지하는 것.
용어
- 리더(master, primary) : 클라이언트가 데이터베이스 쓰기 요청을 할 때 받는 노드
- 플로워(slave, secondary, read replica) : 리더 데이터베이스 정보들을 동기화하는 노드들
최신 용어에 관해 주의할 것
- 복제 알고리즘은 분산 컴퓨팅의 시초라고 생각할 수 있다. 다수의 사용자 요청에 대해서 읽기 처리는 replica, leader에게 분산, 쓰기는 leader에게 몰아주는 방식으로.
- 단순 클라이언트 - 서버 구조가 아니라, 카프카 아키텍쳐 내부에서도 리더-팔로워 개념으로 replication 을 하고 있다. 여러 노드에 replica를 지원하는 많은 아키텍쳐는 이 개념을 사용하고 있다. (최근에는 chain replication 같은 특수한 형태의 복제 방식도 있다)
복제 알고리즘
- 단일 리더(single-leader), 다중 리더(multi-leader), 리더리스(leaderless) 가 대표적으로 있다.
단일 리더
동기식 vs 비동기식 복제
- 동기식: 팔로워가 모두 복제가 다 될때까지 리더가 기다려줌
- 리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장
- But, 팔로워 중 하나 고장나면 데이터베이스 시스템 전체가 고장
- 비동기식: 리더는 변경사항만 팔로워에게 전달하고 자기 할일 함
- 동기식처럼 하나 고장나면 시스템 전체 고장나는 것을 막을 수 있다
- But, 최신 데이터 복사본 가지는 것을 보장 못함
- 반동기식: 두 개 같이 씀.
나의 시스템에 팔로워 노드를 새로 추가한다면 어떻게 해야하나?
- 리더의 데이터베이스 스냅숏(특정 시점까지의 모든 기록)을 가져온다.
- 스탭숏으로 새로운 팔로워 노드에 복사한다.
- 스냅숏 이후 발생한 모든 데이터 변경을 리더에게 요청.
노드가 죽으면 어떻게 하나?
- 팔로워 장애 : 팔로워는 리더로부터 받은 변경 로그를 로컬 디스크에 보관하도록 해야한다. 그리고 나서, 변경 로그에서 결함 발생 전 마지막 트랜잭션 확인 후, 결함 발생 전 트랜잭션 변경 사항 반영 -> 결함 발생 전 트랜잭션 - 최신 변경사항 사이의 정보 리더에게 요구 하면 복구할 수 있다.
- 리더 장애 : 새로운 리더를 선출한다.
- 리더가 장애인지 확인 -> 새로운 리더 선출 -> 새로운 리더 사용을 위해 시스템 재설정(쓰기 operation 새로운 리더에게 가도록 등등)
- 복구 과정에서 생길 수 있는 문제점:
- 리더 장애 -> 새로운 리더 선출 사이에 데이터를 수신 못할 가능성이 있다. 그냥 폐기...
- 새로운 리더 선출 후, 원래 리더가 복귀하면 리더가 2개로 인식되서 split brain 현상 생길 수 있다.
- 제일 처음 리더가 장애인지 확인하는 과정에서, 적절한 타임아웃을 주지 않는다면, 큰일난다.
리더 기반 복제는 내부적으로 어떻게 동작하나?
- 구문 기반 복제
- 쓰기 전 로그 배송
- 논리적 로그 복제
- 트리거 기반 복제
복제에 대한 설계는 어떻게 달라져야 하나?
- 내가 쓴 내용 읽기가 중요한 경우
- ex) 인스타그램에서 프로필 수정을 했는데, 수정이 안되...
- 여러 디바이스에서 접근 할수 있는 앱을 설계할 때 (웹 앱, 모바일 웹 등등)
- 시간에 기반한 자료 (타임라인 등등)를 설계할 때
다중 리더 복제
- CDN
- 단일 리더 복제 로 데이터센터를 구성하면, 리더가 있는 데이터센터로 쓰기 operation을 이동해야 하는데, 지연 시간을 상당히 늘리게 된다. 반면에 다중 리더 복제 의 경우는 데이터 센터별로 독립적으로 리더가 있기 때문에, 네트워크 지연이 훨씬 줄어든다.
- 단/리 의 경우 고장 복구를 위해 데이터센터 들 중 팔로워노드들 중 하나를 리더로 승진시키는데, 이 사이에 이루어지는 쓰기 작업은 무시당할 가능성이 크다.
- 데이터 센터가 장애나도, 쓰기 처리는 계속 될 수 있다.
언제 사용하나?
- 캘린더, 노트 앱과 같이 모두 쓰기를 지원해야하고, 온라인/오프라인 전환이 빈번하면서 동일한 데이터를 동기화해야할 때
- 협업 편집도구 (google note, zoom 등)
쓰기 충돌은 어떻게 해결하나?
- 동기식으로 처리하는 방법 : 모든 복제 서버가 쓰기를 복제하기를 기다린다.
- 비동기식으로 처리하는 방법 :
- 특정 레코드의 쓰기가 동일한 리더를 거치도록 설정한다.
- 우선순위를 만든다. (복제 서버에 고유 ID 부여 후 우선순위를 설정한다던가, 값을 어떻게든 병합한다던가)
- 충돌로그를 모두 보존해 해결 후 다시 반영한다던가
다중 리더 토폴로지
- 첫번째, 두번째를 보완한 토폴로지가 세번째지만 역시 문제점이 있다.
리더 없는 복제
모든 노드가 쓰기 요청을 받을 수 있다. or 제 3자가 특정 순서로 쓰기 작업을 전송해준다.
언제 사용하나?
- High Availability가 정말 중요한 요소인 경우 (ex. 게임)
- 다중 데이터센터 운영
quorum 정하기
- 높은 가용성을 위해, 사용자가 읽기 요청 시, 가장 최신의 데이터를 읽을 수 있도록 지원해야한다.
- 몇 개의 노드에게 쓰기 요청을 할 것인가(w), 몇 개의 노드에게 읽기 요청을 할 것인가 정하는 작업(r)
- w + r > n 이면 일반적으로 모든 읽기는 키의 최신값을 반환할 것을 기대한다
다만 quorum을 정해도 문제점이 있는 경우가 있는데
- 쓰기와 읽기가 동시 발생하는 경우
- 두개의 쓰기가 동시에 발생하는 경우 (앞에 말한 다중 리더 시, 해결방법 참고)
- 같은 키에 쓰기 허용 경우
어떻게 해결하나?
- 이전 발생 관계 파악하기
- 버전 벡터 적용하기
어디에 사용하나?