1. 분산 데이터
1.1. 여러 장비간 분산된 데이터베이스를 필요로 하는 이유
•
확장성
◦
데이터 볼륨, 읽기 부하, 쓰기 부하가 단일 장비에서 다룰 수 있는 양보다 커지면 부하를 여러 장비로 분배 가능
•
내결함성/고가용성
◦
장비 하나가 죽더라도 애플리케이션이 계속 동작해야 한다면 여러 장비를 사용해 중복성 제공 가능
•
지연시간
◦
사용자와 지리적으로 가까운 데이터센터에서 서비스를 제공하기 위해 전 세계 다양한 곳에 서버를 두어 지연을 낮춘다
1.2. 고부하로 확장
1.2.1. 공유 아키텍처
•
수직 확장을 통해 공유 메모리 아키텍처로 단일 장비처럼 다룰 수 있다.
•
하지만 많은 비용이 들고, 병목 때문에 두 배의 용량을 높힌다고 반드시 두 배의 부하를 처리할 수 있는 것이 아니다.
1.2.2. 비공유 아키텍처
•
수평 확장을 통해 독립적인 컴퓨팅 자원을 가지는 노드를 생성한다.
•
가성비가 좋은 시스템을 사용할 수 있고 지리적 영역에 걸쳐 데이터를 분산해 지연시간을 줄일 수 있다.
1.3. 복제 대 파티셔닝
•
복제 = 같은 데이터를 다른 위치에 있는 여러 노드에 유지한다.
•
파티셔닝 = 큰 데이터베이스를 파티션이라는 작은 서브셋으로 나누고 각 파티션은 각기 다른 노드에 할당한다.
2. 복제
•
복제란 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지한다는 의미다.
•
복제가 필요한 이유
◦
지리적으로 사용자와 가깝게 데이터를 유지해 지연 시간을 줄인다.
◦
시스템의 일부에 장애가 발생해도 지속적으로 동작할 수 있게 해 가용성을 높인다.
◦
읽기 질의를 제공하는 장비의 수를 확장해 읽기 처리량을 늘린다.
•
복제에서 모든 어려움은 변경 처리에 있으며 노드가 변경을 복제하기 위한 알고리즘으로 단일 리더, 다중 리더, 리더 리스 복제를 살펴본다.
•
복제는 고려해야 할 트레이드오프가 있다.
2.1. 리더와 팔로워
•
데이터베이스의 복사본을 저장하는 각 노드를 복제 서버(replica)라고 한다.
•
데이터베이스의 모든 쓰기는 모든 복제 서버에 처리돼야 한다.
◦
가장 일반적인 해결책은 리더 기반 복제다.
리더-팔로워 모델
▪
복제 서버 중 하나를 리더로 정하고 리더는 로컬 저장소에 새로운 데이터를 저장한다.
▪
다른 복제 서버는 팔로워가 되어 변경을 복제 로그나 변경 스트림을 통해 전송받아 복사본을 갱신한다.
2.2. 동기식 대 비동기식 복제
동기식과 비동기식의 차이
•
팔로워1은 동기식, 팔로워2는 비동기식 복제를 사용하고 있다.
•
동기식 복제의 장단점
◦
리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장
◦
동기 팔로워가 응답하지 않는다면 쓰기가 처리될 수 없다.
▪
리더는 모든 쓰기를 block하고 동기 복제 서버가 다시 사용할 수 있을 때까지 기다려야 한다.
◦
때문에 모든 시스템이 동기식이라면 전체 시스템이 멈추게 된다.
•
동기식, 비동기식을 섞어 사용하는걸 반동기식이라 한다.
•
보통 리더 기반 복제는 완전히 비동기식으로 구성한다.
•
비동기식 복제는 내구성을 약화시키기 때문에 나쁜 트레이드오프 같지만 많은 팔로워가 있거나 지리적으로 분산됐다면 비동기식 복제를 널리 사용한다.
2.3. 새로운 팔로워 설정
•
때때로 복제 서버 수를 늘리거나 장애 노드의 대체를 위한 새로운 팔로워를 설정해야 한다.
•
클라이언트는 지속적으로 DB에 기록하고 데이터는 항상 유동적이기 때문에 표준 파일 복사본은 다른 시점에 데이터베이스의 다른 부분을 보게 된다.
◦
즉 복사 결과가 유효하지 않을 수 있다.
•
DB를 잠가 디스크의 일관성을 만들 수 있지만 고가용성 목표에 부합하지 않기 때문에 아래 과정을 통해 진행한다.
◦
DB잠금을 걸지 않고 리더의 스냅숏을 일정 시점에 가져온다. (MySQL의 innobackupex 툴)
◦
스냅숏을 새로운 팔로워에 복사한다.
◦
팔로워는 리더에 연결해 스냅숏 이후 데이터 변경을 요청한다. (로그 일련번호와 이진로그 좌표를 통해 진행)
◦
팔로워가 스냅숏 이후 데이터 변경의 미처리분을 모두 처리했을 때 따라잡았다고 말한다.
2.4. 노드 중단 처리
•
노드가 장애로 인해 예기치 않게 중단될 경우 리더 기반 복제에서 고가용성을 달성할 수 있는 방법
2.4.1. 팔로워 장애: 따라잡기 복구
•
결함이 발생하기 전 마지막 트랜잭션을 알아내 끊어진 이후 발생한 데이터 변경을 모두 요청한다.
2.4.2. 리더 장애: 장애 복구
•
리더의 장애를 처리하는 일은 까다롭다 팔로워 중 하나를 리더로 승격하고 클라이언트는 새로운 리더로 쓰기를 전송해야하는 재설정이 필요하다.
•
장애 복구 단계
◦
리더가 장애인지 판단한다.
◦
새로운 리더를 선택한다.
◦
새로운 리더 사용을 위해 시스템을 재설정 한다.
2.5. 복제 로그 구현
2.5.1. 구분 기반 복제
•
리더는 모든 쓰기 요청을 기록하고 쓰기를 실행한 다음 구문 로그를 팔로워에게 전송한다.
•
합리적인 것 같은 이 접근법도 복제가 깨질 수 있는 사례가 존재한다.
◦
NOW(), RAND() 등은 복제 서버마다 다른 값을 생성할 가능성이 존재
◦
자동증가 컬럼을 사용하거나, 기존 데이터에 의존하는 경우(WHERE) 정확히 같은 순서로 실행되어야 함
◦
순서가 다르면 구문의 효과가 다를 수 있음 → 동시에 여러 트랜잭션이 수행되는 것을 제한한다.
◦
부수효과를 가진 구문의 경우 부수효과가 완벽히 결정적이어야 모든 팔로워에서 그 효과도 동일하다.
◦
트리거, 스토어드 프로시저, 사용자 정의 함수
•
이 문제의 해결책으로 리더는 구문을 기록할 때 모든 비결정적 함수 호출을 고정 값을 반환하게끔 대체할 수 있다.
◦
But. 여러 에지 케이스가 있기에 일반적으로 다른 복제 방법을 선호한다.
2.5.2. 쓰기 전 로그 배송
•
일반적으로 데이터베이스의 모든 쓰기는 로그에 기록이 된다.
•
리더가 로그를 팔로워에게 전송하고, 팔로워는 이 로그를 처리함으로써 복제한다.
•
로그는 제일 저수준의 데이터를 기술함
◦
디스크 블록에서 어떤 데이터를 변경했는 지와 같은 상세 정보 포함
◦
복제 프로세스가 저장소 엔진과 밀접하게 연관된다.
◦
리더와 팔로워가 동일한 소프트웨어 버전에서 실행되어야 한다.
◦
소프트웨어 업그레이드 시 중단 시간이 필요하다.
2.5.3. 논리적(로우 기반) 로그 복제
•
로그를 저장소 엔진과 분리하기 위한 대안으로 복제와 저장소 엔진에 각기 다른 로그 형식을 사용한다.
•
이와 같이 복제에서 사용하는 로그를 저장소 엔진의 물리적 데이터 표현과 구별하기 위해 논리적 로그라 부른다.
•
RDB의 논리적 로그는 대개 로우 단위이고, 테이블에 쓰기를 기술한 레코드 열이다.
◦
삽입된 로우 = 모든 컬럼의 새로운 값을 포함
◦
삭제된 로우 = 로우를 식별하기 위한 정보(보통 기본 키)를 포함
◦
갱신된 로우 = 로우를 식별하기 위한 정보 + 모든 컬럼의 새로운 값 또는 변경된 컬럼의 새로운 값
•
여러 로우를 수정하는 트랜잭션은 여러 로그 레코드를 생성한 다음 트랜잭션 커밋을 레코드에 표시한다.
•
논리적 로그와 저장소 엔진 내부를 분리해 하위 호환성을 쉽게 유지하고, 리더와 팔로워간 다른 버전의 소프트웨어 실행이 가능
•
논리적 로그는 외부 애플리케이션이 파싱하기 쉽다.
◦
데이터 웨어하우스와 같은 외부 시스템에 데이터베이스 내용 전송 시 유용하다.
◦
변경 데이터 캡쳐(CDC, change data capture)
2.5.4. 트리거 기반 복제
•
지금까지 설명한 복제 방식은 애플리케이션의 관여 없이 DB 시스템에 의해 구현되었다.
•
오라클은 GoldenGate 도구를 통해 데이터베이스 로그를 읽어 애플리케이션이 데이터를 변경할 수 있도록 한다.
•
사용자 정의 애플리케이션 코드를 등록할 수 있다.
•
데이터 변경 시(쓰기 트랜잭션) 자동으로 실행된다.
•
트리거를 통해 데이터 변경을 분리된 테이블에 로깅한다.
•
이 테이블에 기록된 데이터 변경을 외부 프로세스가 읽고 처리한다.
•
필요한 애플리케이션 로직 적용 후 다른 시스템에 데이터 변경을 복제한다.
•
트리거의 장점
◦
유연성 높아 매우 유용하다.
•
트리거의 단점
◦
트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있다.
◦
그리고 데이터베이스에 내장된 복제보다 버그나 제한 사항이 더 많이 발생한다.
2.6. 복제 지연 문제
•
복제는 노드 내결함성 뿐만 아닌 확장성과 지연 시간 때문에도 필요하다.
•
읽기 확장 아키텍쳐
◦
리더 기반 복제는 쓰기 분산은 어렵지만 읽기 분산이 가능하다.
◦
장점
▪
웹 서비스의 경우 읽기 요청이 대부분, 쓰기 요청은 작은 비율로 구성
▪
리더의 부하를 경감하고 복제 서버에서 읽기 요청을 처리 → 웹 서비스에 적합
▪
복제의 목표 중 확장성, 지연시간 단축 달성
◦
단점
▪
비동기식 복제 방식에서만 동작한다.
▪
동기식 복제는 단일 노드의 장애, 네트워크 중단이 전체 시스템의 쓰기를 마비시켜 적절하지 않음
▪
노드가 많아질 수록 다운될 가능성이 커져 동기식 설정과 적절하지 않다.
•
데이터 불일치 = 팔로워와 리더간 일시적 복사 지연 상태
•
최종적 일관성 = 팔로워는 리더와 데이터의 불일치 상태가 있을 수 있지만 쓰기를 멈추면 결국 리더를 따라잡게 된다.
•
복제 지연으로 인한 데이터 불일치는 찰나의 순간이고 크게 문제가 되지 않지만 시스템이 가용량 근처에서 동작하거나 네트워크 문제가 있다면 복제 지연으로 인한 불일치가 문제가 된다.
2.6.1. 복제지연 사례
자신이 쓴 내용 읽기
단조 읽기
일관된 순서로 읽기
2.6.2. 복제 지연 해결책
•
해결 방안의 종류
◦
쓰기 후 읽기와 같은 강한 보장을 제공하도록 시스템을 설계한다.
▪
비동기식 복제를 사용하지만 동기식 방식으로 동작하는 것 처럼 보인다.
◦
애플리케이션이 데이터베이스보다 더 강력한 보장을 제공하는 방법도 있다.
▪
그러나 애플리케이션에서 다루기에는 복잡하여 잘못되기 쉽다.
•
트랜잭션 = 애플리케이션이 단순해지기 위해 데이터베이스가 더 강력한 보장을 제공하는 방법
◦
애플리케이션 개발자가 미묘한 복제 문제를 걱정하지 않고 올바른 작업 수행을 위해 항상 데이터베이스를 신뢰할 수 있다.
◦
이것이 트랜잭션이 존재하는 이유다.
•
분산 시스템에서의 트랜잭션은 많은 시세틈에 포기했다.
◦
트랜잭션은 가용성과 성능 측면에서 너무 비싸다.
◦
확장 가능한 시스템에서는 최종적 일관성을 선택하는 것이 불가피하다는 주장도 존재한다.
◦
이러한 주장의 일부는 사실이지만 지나치게 단순화된 측면이 있다.
3. 다중 리더 복제
•
리더 기반 복제는 하나의 리더를 거쳐야만 쓰기가 가능하다는 것이다.
•
쓰기 처리를 하는 각 노드는 데이터 변경을 모든 노드에 전달하는데 이를 다중 리더 설정이라 부른다.
◦
이 설정에서 각 리더는 동시에 다른 리더의 팔로워 역할도함
◦
모든 쓰기를 해당 리더를 거쳐야 하고, 리더 연결이 불가능한 경우 쓰기 불가능한 단점 보완
3.1 다중 리더 복제의 사용 사례
3.1.1 다중 데이터 센터 운영
•
각 데이터 센터마다 리더가 있을 수 있다.
•
각 데이터 센터내 리더 팔로워 복제를 사용
•
각 데이터 센터 간 리더가 다른 데이터 센터 리더에게 변경 사항 복제한다.
•
동일한 데이터를 다른 두 개의 데이터센터에서 동시에 변경 가능하므로 쓰기 충돌은 반드시 해소되어야함
•
일부 데이터베이스는 기본적으로 다중 리더 설정 제공
•
단일 리더와 다중 리더간의 설정 비교
# | 단일 리더 | 다중 리더 |
성능 | 쓰기는 인터넷을 통해 리더가 있는 데이터 센터로 이동해야해서 쓰기 지연 발생 | 쓰기는 로컬 데이터센터 처리 후 비동기 방식으로 다른 데이터센터에 복제 |
데이터센터 중단 내성 | 리더가 있는 데이터센터가 고장 나면 다른 데이터센터의 팔로워를 리더로 승진 | 각 데이터센터 독립적으로 동작, 고장난 데이터센터가 온라인으로 돌아왔을때 복제 |
네트워크 문제 내성 | 데이터 센터 내 쓰기는 동기식이기에 데이터 센터 내 연결 문제에 민감 | 비동기 복제를 사용해 네트워크 문제에 보다 잘 견딤, 일시적 네트워크 중단에도 쓰기 처리는 진행되기 때문 |
3.1.2. 오프라인 작업을 하는 클라이언트
•
인터넷 연결이 끊어진 동안 애플리케이션 동작해야 하는 경우
•
협업 편집 : 동시에 여러 사람이 문서를 편집할 수 있는 애플리케이션 ex) 이더패드, 구글 독스 등
3.2. 쓰기 충돌 다루기
•
다중 리더 복제에서 가장 큰 문제는 쓰기 충돌이 발생한다는 점이다.
•
각 사용자가 동시에 편집 후 로컬 리더에 저장하였으나 변경을 비동기로 복제 시 쓰기 충돌 발생
3.2.1. 동기 대 비동기 충돌 감지
•
동기식으로 충돌 감지를 하면 다중 리더 복제의 장점을 잃어버림
3.2.2. 충돌 회피
•
충돌 처리하는 가장 간단한 전략
•
충돌 처리가 어려워 충돌 피하는 것이 자주 권장됨
•
특정 레코드의 모든 쓰기를 동일한 리더에서 처리함
3.2.3. 일관된 상태 수렴
•
모든 복제 서버가 동일해야 하는 원칙으로 일괄성없는 상태를 용인하지 않는다.
•
수렴(convergent) : 모든 변경이 복제돼 모든 복제 서버에 동일한 최종 값이 전달되게 해야 함
3.2.4. 사용자 정의 충돌 해소 로직
•
충돌 해소의 가장 적합한 방법은 애플리케이션에 따라 다르다.
•
따라서 대부분 다중 리더 복제도구는 애플리케이션 코드를 사용해 충돌 해소 로직 작성
쓰기 수행 중 | - 복제된 변경사항 로그에서 데이터베이스 시스템 충돌 감지되면 충돌 핸들러 호출
- 백그라운드에서 실행됨 |
읽기 수행 중 | - 충돌 감지 시 모든 충돌 쓰기 저장
- 다음 번 읽기 시 여러 데이터 반환. 애플리케이션은 사용자에게 충돌 내용 보여주거나 자동으로 충돌 해소해 결과를 데이터베이스에 기록
- 카우치DB가 이렇게 동작 |
•
자동 충돌 해소
◦
충돌 없는 복제 데이터 타입
▪
Set, Map, 정렬 목록, 카운터 등을 위한 데이터 구조의 집합
◦
병합 가능한 영속 데이터 구조
▪
Git 처럼 명시적으로 히스토리 추적하고 삼중 병합 함수를 사용한다
◦
운영 변환
▪
이더패트, 구글 독스 같은 협업 편집 애플리케이션의 충돌 해소 알고리즘
3.3. 다중 리더 복제 토폴로지
•
복제 토폴로지는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명
•
리더가 둘 이상이라면 다양한 토폴로지가 가능하다.
•
원형 토폴로지
◦
각 노드가 하나의 노드로부터 쓰기를 받고, 이 쓰기를 다른 노드에 전달
◦
MySQL 에서 기본적으로 제공
◦
노드 장애 시 노드 간 복제 메시지 흐름에 방해를 줌
•
별 모양 토폴로지
◦
지정된 루트 노드 하나가 다른 모든 노드에 쓰기 전달
◦
트리로 일반화 가능
◦
노드 장애 시 노드 간 복제 메시지 흐름에 방해를 줌
다중 리더 복제의 쓰기가 잘못된 순서로 도착할 수 있다.
•
전체 연결 토폴로지
◦
모든 리더가 각자의 쓰기를 다른 모든 리더에 전송
◦
가장 일반적인 토폴로지
◦
내결함성이 상대적으로 좋음
◦
전체 연결 토폴로지의 문제점
▪
네트워크 연결 속도 차이로 인한 복제 메시지 추월
▪
리더2는 삽입 이전에 갱신을 처리하게 됨
▪
올바른 이벤트 정렬을 위한 버전 벡터 기법으로 해결 가능
▪
따라서 다중 리더 복제 시스템을 사용하려면 이런 문제를 인지하고 문서를 주의깊게 읽은 다음 데이터 베이스를 철저하게 테스트해봐야 함
4. 리더 없는 복제
•
리더의 개념을 버리고 복제 서버가 클라이언트로부터 쓰기를 직접 받을 수 있게 허용하는 접근 방식
•
다이나모 스타일 DB로 리악, 카산드라, 볼드모트 등 오픈소스 데이터스토어가 있음
•
일부 리더 없는 복제 구현에서는 클라이언트가 여러 복제 서버에 쓰기를 직접 전송하는 반면 코디네이터 노드가 클라이언트를 대신해 이를 수행하기도 한다.
4.1. 노드가 다운됐을 때 데이터베이스에 쓰기
정족수(quorum) 쓰기, 정족 수 읽기와 노드 중단 후 읽기 복구
•
다운된 노드에서는 쓰기가 누락되어 오래된(outdated) 값을 읽게 됨
•
읽기 요청을 병렬로 여러 노드에 전송해 최신 값을 읽어와 해결 가능
•
버전 숫자를 통해 읽어온 값 중 최신 값을 결정함
4.1.1. 읽기 복구와 안티 엔트로피
•
복제 계획은 최종적으로 모든 데이터가 모든 복제 서버에 복사된 것을 보장해야 한다.
•
다이나모 스타일 데이터스토어는 두 가지 메커니즘을 주로 사용
읽기 복구 | - 클라이언트가 여러 노드에서 병렬로 읽기 수행하면 오래된 응답 감지 가능
- 복제 서버의 오래된 값을 새로운 값으로 기록
- 값을 자주 읽는 상황에 적합 |
안티 엔트로피 처리 | - 백그라운드 프로세스와 복제 서버 간 데이터 차이를 찾아 누락된 데이터를 복사
- 특정 순서로 쓰기를 복사하기 때문에 지연이 있을 수 있음 |
4.1.2. 읽기와 쓰기를 위한 정족수
•
모든 성공한 쓰기가 세 개의 복제 서버 중 적어도 두 개의 복제 서버에 존재한다는 것을 보장한다면 하나의 복제 서버가 오래된 데이터임을 의미
◦
두 개의 복제 서버에서 읽으면 두 개 중 적어도 하나는 최신 값인지 확인할 수 있다.
◦
n개의 복제 서버가 있을 때 w개의 노드에서 성공해야 쓰기가 확정되고 모든 읽기는 최소한 r개의 노드에 질의해야 한다.
▪
이런 r과 w를 따르는 읽기와 쓰기를 정족수 읽기와 쓰기라 부른다.
◦
다이나모 스타일 DB에서는 복제 서버(n), 쓰기 노드(w), 읽기 노드(r) 설정 가능하다.
▪
일반적으로 n 은 3 또는 5 등의 홀수, w = r = (n+1) / 2 (반올림) 설정한다.