-
[데이터 중심 애플리케이션] 복제(분산 데이터)Software Development/Database 2021. 10. 16. 19:19
여러 장비 간 분산된 데이터베이스를 필요로 하는 이유
확장성: 데이터 볼륨, 읽기 부하. 쓰기 부하가 단일 장비에서 다룰 수 있는 양보다 커지면 부하를 여러 장비로 분배할 수 있다.
내결함성/고가용성: 장비 하나가 죽더라도 애플리케이션이 계속 동작해야 한다면 여러 장비를 사용해 중복성을 제공할 수 있다. 장비 하나가 실패하면 다른 하나가 이어받는다.
지연 시간: 사용자와 지리적으로 가까운 곳의 데이터센터에서 서비스를 제공하기 위해 전 세계 다양한 곳에 서버를 두고 싶을 것이다.
고부하로 확장
더 강력한 장비를 구매하는 것이 가장 간단한 방법. 많은 CPU, 많은 메모리 팁, 많은 디스크를 하나의 운영체제로 함께 결합할 수 있다. 빠른 상호 연결로 모든 CPU가 메모리나 디스크의 모든 부분에 접근할 수 있다. 이런 공유 메모리 아키텍처에서는 모든 구성 요소를 단일 장비처럼 다룰 수 있다.
공유 메모리 아키텍처 문제점
1. 비용이 선형적인 추제보다 훨씬 빠르게 증가. 병목현상 때문에 두 배 이상의 비용이 반드시 두 배의 부하를 처리할 수 있는 것은 아니다.
2. 제한적인 내결함성을 제공.
다른 접근 방식으로 공유 디스크 아키텍처가 있다.
독립적인 CPU, RAM을 탑재한 여러 장비를 사용하지만 데이터 저장은 장비 간 공유하는 디스크 배열에 저장한다. 여러 장비는 고속 네트워크 NAS, SAN으로 연결된다. 잠금경합 및 오버헤드가 공유 디스크 접근 방식의 확장성을 제한한다.
비공유 아키텍처(수평 확장, 규모 확장)
데이터베이스 소프트웨어를 수행하는 각 장비나 가상 장비를 노드라고 부른다. 각 노드는 CPU, RAM, 디스크를 독립적으로 사용. 노드 간 코디네이션은 일반적인 네트워크를 사용해 소프트웨어 수준에서 수행.
1. 가격대비 성능이 가장 좋은 시스템
복제 대 파티셔닝
복제: 같은 데이터의 복사본을 잠재적으로 다른 위치에 있는 여러 노드에 유지한다. 복제는 중복성을 제공. 일부 노드가 사용 불가능 상태라면 해당 데이터는 남은 다른 노드를 통해 여전히 제공할 수 있다. 복제는 성능 향상에도 도움이 된다.
파티셔닝: 큰 데이터베이스를 파티션이라는 작은 서브셋으로 나누고 각 파티션은 각기 다른 노드에 할당(샤딩).
복제
복제란 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지한다는 의미.
1. 지리적으로 사용자와 가깝게 데이터를 유지해 지연 시간을 줄인다.
2. 시스템의 일부에 장애가 발생해도 지속적으로 동작할 수 있게 해 가용성을 높인다.
3. 읽기 질의를 제공하는 장비의 수를 확장해 읽기 처리량을 늘린다.
복제 중인 데이터가 시간이 지나도 변경되지 않는다면 복제는 쉽다. 한번에 모든 노드에 데이터를 복사하면 된다.
복제에서 모든 어려움은 복제된 데이터의 변경 처리에 있다.
노드 간 변경을 복제하기 위한 세 가지 인기 있는 알고리즘인 단일 리더, 다중 리더, 리더 없는 복제를 살펴본다. 거의 모든 분산 데이터베이스는 이 세 가지 방법 중 하나를 사용. 각 알고리즘은 장단점이 존재.
리더와 팔로워
데이터베이스의 복사본을 저장하는 각 노드를 복제 서버라고 한다. 다중 복제 서버를 사용하면 필연적으로 궁금증이 생긴다. 모든 복제 서버에 모든 데이터가 있다는 사실을 어떻게 보장할 수 있을까?
데이터베이스의 모든 쓰기는 모든 복제 서버에서 처리돼야 한다. 그렇지 않으면 동일한 데이터를 유지할 수 없다.
해결책은 리더 기반 복제(능동 수동, 마스터 슬레이브 복제라고도 함)다.
복제 서버 중 하나를 리더로 지정한다.
클라이언트가 데이터베이스에 쓰리글 할 때 클라이언트는 요청을 리더에게 보내야 한다. 리더는 먼저 로컬 저장소에 새로운 데이터를 기록.
다른 복제 서버는 팔로워, 슬레이브, 2차 핫 대기라고 한다.
리더가 로컬 저장소에 새로운 데이터를 기록할 때마다 데이터 변경을 복제 로그나 변경 스트림의 일부로 팔로워에게 전송한다.
각 팔로워가 리더로부터 로그를 받으면 리더가 처리한 것과 동일한 순서로 모든 쓰기를 적용해 그에 맞게 데이터베이스의 로컬 복사본을 갱신.
이 복제 모드는 포스트그레스, MYSQL, Oracle 서버의 상시 가용성 그룹과 같은 여러 관계형 데이터베이스에 내장된 기능이다. 몽고DB, 리싱크DB 등 일부 비관계형 데이터베이스에서도 사용한다. 마지막으로 리더 기반 복제는 데이터베이스에만 국한되지 않는다. 카프카와 래빗MQ의 고가용성 큐 같은 분산 메세지 브로커에도 사용된다. 네트워크 파일 시스템과 DRBD 같은 복제 블럭 디바이스도 유사하다.
동기식 대 비동기식 복제
어떤 시점에서 클라이언트는 갱신 요청을 리더에게 전송. 곧 리더는 요청을 받고, 어떤 시점에서 리더는 데이터 변경을 팔로워에게 전달. 최종적으로 리더는 클라이언트에게 생긴이 성공했음을 전달.
보통 복제는 매우 빨라 1초 내에 팔로워에게 변경 내용을 적용하지만 얼마나 오래 걸릴지는 보장할 수 없다. 팔로워가 수분 이상 리더와 떨어질 수 있다. 팔로워가 장애를 복구 중이거나 시스템이 최대 가용량 부근에서 동작하거나 노드 간 네트워크 문제가 있을 수 있기 때문이다.
동기식 장점: 팔로워가 리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장. 리더가 작동하지 않아도 데이터는 팔로워에서 계속 사용할 수 있음을 확신할 수 있다. 단점은 동기 팔로워가 응답하지 않는다면 쓰기가 처리될 수 없다는 것이다. 리더는 모든 쓰기를 차단하고 동기 복제 서버가 다시 사용할 수 있을 때까지 기다린다.
모든 팔로워가 동기식인 상황은 비현실적이다. 한 노드의 장애는 전체 시스템의 장애로 이어짐.
보통 리더 기반 복제는 완전히 비동기식으로 구성. 리더가 잘못되고 복구할 수 없으면 팔로워에 아직 복제되지 않은 모든 쓰기는 유실. 이것은 쓰기가 클라이언트에게 확인된 경우에도 지속성을 보장하지 않음. 하지만 팔로워가 잘못되더라도 리더가 쓰기 처리를 계속할 수 있는 장점이 있다.
새로운 팔로워 설정
새로운 팔로워가 리더의 데이터 복제본을 정확히 가지고 있는지 어떻게 보장할까?
간단히 한 노드에서 다른 노드로 데이터 파일을 복사하는 것만으로는 대개 충분하지 않다.
데이터베이스를 잠가서(쓰기 불가능) 디스크의 파일을 일관성 있게 만들 수 있지만 고가용성 목표에 부합하지 않는다. 다행히 팔로워 설정은 중단없이 가능하다.
1. 가능하다면 전체 데이터베이스를 잠그지 않고 리더의 데이터베이스 스냅숏을 일정 시점에 가져온다. 대부분의 데이터베이스는 백업이 필요하기 때문에 이 기능을 갖췄다.
2. 팔로워는 리더에 연결해 스냅숏 이후 발생한 모든 데이터 변경을 요청한다. 이것은 스냅숏이 리더의 복제 로그의 정확한 위치와 연관돼야 한다.
3. 팔로워가 스냅숏 이후 데이터 변경의 미처리분(backlog)을 모두 처리했을 때 따라잡았다고 말한다. 이제부터 리더에 발생하는 데이터 변화를 이어 처리할 수 있다.
노드 중단 처리
시스템의 모든 노드는 장애로 인해 예기치 않게 중단될 수 있지만 계획된 유지보수로 인해 중단될 수도 있다. 중단 시간 없이 개별 노드를 재부팅 할 수 있다는 점은 운영과 유지보수에 큰 장점이 있다.
팔로워 장애: 따라잡기 복구
각 팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관한다. 팔로워가 죽어 재시작하거나 리더와 팔로워 사이의 네트워크가 일시적으로 중단된다면 팔로워는 매우 쉽게 복구할 수 있다.
먼저 보관된 로그에서 결함이 발생하기 전에 처리한 마지막 트랜잭션을 알아낸다. 그러면 팔로워는 리더에 연갤해 팔로워 연결이 끊어진 동안 발생한 데이터 변경을 모두 요청할 수 있다.
리더 장애: 장애 복구
팔로워 중 하나를 새로운 리더로 승격해야 하고 클라이언트는 새로운 리더로 쓰기를 전송하기 위해 재설정이 필요하며 다른 팔로워는 새로운 리더로부터 데이터 변경을 소비하기 시작해야 한다.
장애 복구는 수동 혹은 자동으로 진행한다. 자동 복구는 다음과 같다.
1. 리더가 장애인지 판단한다. 고장, 정전, 네트워크 문제 등 잠재적으로 여러 가지가 잘못될 수 있다. 무엇이 잘못됐는지 발견할 수 있는 확실한 방법이 없기 때문에 타임아웃을 사용한다.
2. 새로운 리더를 선택한다. 이것은 선출 과정을 통해 이뤄지거나 이전에 선출된 제어 노드에 의해 새로운 리더가 임명될 수 있다. 새로운 리더로 가장 적합한 후보는 보통 이전 리더의 푀신 데이터 변경사항을 가진 복제 서버다.
3. 새로운 리더 사용을 위해 시스템을 재설정한다. 클라이언트는 새로운 쓰기 요청을 새로운 리더에게 보내야한다.
장애 복구 과정에서의 잘못된 가능성
1. 비동기식 복제를 사용한다면 새로운 리더는 이전 리더가 실패하기 전에 이전 리더의 쓰기를 일부 수신하지 못할 수 있다. 이전 리더의 복제되지 않은 쓰기를 단순히 폐기할 수 있으나 내구성에 대한 클라이언트의 기대를 저버린다.
2. 쓰기를 폐기하는 방법은 데이터베이스 외부의 다른 저장소 시스템이 데이터베이스 내용에 맞춰 조정돼야 한다면 특히 위험하다.
3. 특정 결함 시나리오에서 두 노드가 모두 자싱이 리더라고 믿을 수 있다.
4. 리더가 분명히 죽었다고 생각할 적절한 타임아웃은 얼마일까?
이 문제에 대한 쉬운 해결책은 없다. 이런 이유로 일부 운영팀은 소프트웨어가 자동 장애 복구를 지원하더라도 수동으로 장애 복구를 수행하는 방식을 선호한다.
복제 로그 구현
구문 기반 복제
리더는 모든 쓰기 요청(구문)을 기록하고 쓰기를 실행한 다음 구문 로그를 팔로워에게 전송한다. 합리적으로 보이지만 복제가 깨질 수 있는 다양한 사례가 있다.
1. 현재 날짜와 시간을 얻기 위한 NOW()나 임의 숫자를 얻기 위한 RAND() 같은 비결정적인 함수를 호출하는 모든 구문은 각 보제 서버마다 다른 값을 생성할 가능성이 있다.
2. 자동증가 컬럼을 사용하는 구문이나 데이터베이스에 있는 데이터에 의존한다면 구문은 각 복제 서버에서 정확히 같은 순서로 실행돼야 한다. 그렇지 않으면 효과가 달라질 수 있다.
3. 부수 효과를 가진 구문은 부수 효과가 완벽하게 결정적이지 않으면 각 복제 서버에서 다른 부수 효과가 발생할 수 있다.
비결정적인 함수 호출을 고정 값을 반환하게끔 대체할 수 있지만 여러 에지케이스가 있기 때문에 다른 복제 방법을 선호한다. 만일 구문에 비결정성이 있다면 기본적으로 로우 기반 복제로 본경한다.
쓰기 전 로그 배송
리더는 디스크에 로그를 기록하는 일 외에도 팔로워에게 네트워크로 로그를 전송.
포스크그레스와 오라클에서 사용. 단점을 로그가 제일 저수준의 데이터를 기술한다는 점이다. WAL은 어떤 디스크 블록에서 어떤 바이트를 변경했는지와 같은 상제 정보를 포함한다. 이는 복제가 저장소 엔진과 밀접하게 엮인다. 소프트웨어 업에이트 시 중단시간이 필요하다.
논리적(로우 기반)로그 복제
저장소 엔진의 물리적데이터 표현과 구별하기 위해 논리적 로그 형식을 사용.
여러 로우를 수정하는 트랜잭션은 여러 로그 레코드를 생성한 다음 트랜잭션이 커밋됐음을 레코드에 표시한다. 논리적 로그를 저장소 엔진 내부와 분리했기 때문에 하위 호환성을 더 쉽게 유지할 수 있고 리더와 팔로워에서 다른 버전의 데이터베이스 소프트웨어나 심지어 다른 저장소 엔진을 실행할 수 있다.
또한 논리적 로그 형식은 외부 애플리케이션이 파싱하기 더 쉽다.
트리거 기반 복제
트리거는 사용자 정의 애플리케이션 코드를 등록할 수 있게 한다. 이 애플리케이션 코드는 데이터베이스 쓰템에서 데이터가 변경되면 자동으로 실행된다. 트리거는 데이터 변경을 분리된 테이블에 로깅할 수 있는 기회를 가진다. 외부 프로세스가 읽을 수 있고 필요한 애플리케이션 로직을 적용해 다른 시스템으로 데이터 변경을 복제한다. 제한 사항이 더 많지만 유연성이 강점이다.
복제 지연 문제
노드 내결함성을 갖추려는 단 한 하기 이유는 복제가 필요하기 때문이다. 리더 기반 복제에서 쓰기는 단일 노드를 거쳐야 하지만 읽기 전용 질의는 어떤 복제 서버에서도 가능하다. 팔로워 추가를 통해서 일기 전용 요청을 처리하기 위한 용량을 늘릴 수 있다. 하지만 비동기식 족제에서만 동작한다.
데이터의 일시적인 불일치가 발생할 수 있지만 일시적일 뿐이다. 이런 효과를 최종적 일관성이라 한다.
자신이 쓴 내용 읽기
새로운 데이터가 제출되면 리더에게 전송해야 하지만 사용자가 데이터를 볼 때는 팔로워에서 읽을 수 있다. 자신이 쓴 내용만 일관성을 보장하는 법
1. 사용자가 수정한 내용을 읽을 때는 리더에서 읽는다. 그 밖에는 팔로워에서 읽는다.
2. 애플리케이션 내 대부분의 내용을 사용자가 편집할 가능성이 있다면 이 접근 방식은 대부부분 리더에서 읽기 땜누에 효율적이지 않다.
3. 클라이언트는 가장 최근 쓰기의 타임스탬프를 기억할 수 있다. 그러면 시스템은 사용자 읽기를 위한 복제 서버가 최소한 해당 타임스탬프까지 갱신을 반영하게 할 수 있다.
4. 복제 서버가 여러 데이터센터에 분산됐다면 복잡도가 증가한다.
단조 읽기
비동기식 팔로워에서 읽을 때 발생할 수 있는 두 번째 이상 현상은 사용자가 시간이 거꾸로 흐르는 현상을 목격할 수 있다는 것.
단조 읽니는 이런 종류의 이상 현상이 발생하지 않음을 보장한다.
사용자의 읽기가 항상 동일한 복제 서버에서 수행되게끔 하는 것이다.
일관된 순서로 읽기
세 번째 복제 지연 이상 현상은 인과성의 위반 우려다. 해결책은 인과성이 있는 쓰기가 동일한 파티션에 기록되게끔 하는 방법이다.
다중 리더 복제
리더 기반 복제 모델은 쓰기를 허용하는 노드를 하나 시아 두는 것으로 자연스럽게 확장된다. 복제는 같은 방식을 사용한다. 쓰기 처리를 하는 노드는 데이터 변경을 다른 모든 노드에 전달해야 한다. 이 방식을 다중 리더 설정이라 부른다(마스터 마스터, 액티브 액티브).
다중 리더 복제의 사용 사례
단일 데이터센터 내에 다중 리더 설정을 사용하는 설정은 이로 인해 추가된 복잡도에 비해 이점이 크지 않다. 몇 가지 상황에서는 이 설정이 합리적이다.
다중 데이터센터 운영
다중 리더 설정에서는 각 데이터센터마다 리더가 있을 수 있다. 각 데이터센터 내에는 보통의 리더 팔로워 복제를 상ㅇ하고 데이터센터 간에는 각 데이터센터의 리더가 다른 데이터센터의 리더에게 변경 사항을 복제한다.
단일 리더 설정과 다중 리더 설정이 다중 데이터센터 배포에서 어떻게 이뤄지는지 비교
성능: 단일 리더 설정에서 모든 쓰기는 인터넷을 통해 리더가 있는 데이터센터로 이동해야 한다. 쓰기 지연 시간을 늘린다. 다중 리더 설정에서 모든 쓰기는 로켈 데이터센터에서 처리한 다음 비동기 방식으로 다른 데이터센터에 복제한다. 따라서 데이터센터 간 네트워크 지연은 사용자에게 숨겨진다. 사용자가 인지하는 성능은 더 좋다는 뜻이다.
데이터센터 중단 내성: 단일 리더 설정에서는 리더가 있는 데이터센터가 고장 나면 장애 복구를 위한 다른 데이터센터에서 한 팔로워를 리더로 승격시킨다. 다중 리더 설정에서는 각 데이터센터는 다른 데이터센터와 독립적으로 동작하고 고장 난 데이터센터가 온라인으로 돌아왔을 때 복제는 따라잡는다.
네트오크 문제 내성: 데이터센터 간 트래픽은 보통 공개 인터넷을 통해 처리한다. 데이터센터 내의 로컬 네트워크보다 안정성이 떠러진다. 단일 리더 설정세너는 데이터센터 내 연결의 쓰기는 동기식이기 때문에 데이터센터 내 연결 문제에 매우 민감하다. 비동기 복제를 사용하는 다중 리더 설정에서는 네트워크 문제에 보다 잘 견딘다.
일부 데이터베이스는 기본적으로 다중 리더 설정을 제공한다.
다중 리더 복제의 큰 단점은 동일한 데이터를 다른 두 개의 데이터 센터에서 동시에 변경할 수 있다. 이떄 발생하는 쓰기 충동은 반드시 해소해야 한다.
오프라인 작업을 하는 클라이언트
인터넷 연결이 끊어진 동안 애플리케이션이 계속 동작해야 하는 경우다.
협업 편집
구글 독스, 노션 등의 애플리케이션에서 더 빠른 협업을 위해 변경 단위를 매우 작게해서 잠금을 피할 수 있다. 이 접근 방식은 여러 사용자가 동시에 편집할 수 있지만 충동 해소가 필요한 경우를 포함해 다중 리더 복제에서 발생하는 모든 문제를 야기한다.
쓰기 충동 다루기
다중 리더 복제에서 제일 큰 문제는 쓰기 충돌이 발생한다는 점이다.
충돌 회피
동일한 데이터센터에로 항상 라우팅하고 데이터센터 내 리더를 사용해 읽기와 쓰기를 하게끔 보장할 수 있다.
그러나 데이터센터가 고장 나서 트래픽을 다르 데이터센터로 다시 라우팅해야 하거나 사용자가 다른 지역으로 이동해 현재는 다른 데이터센터가 가깝다면 레코드를 위해 지정된 리더를 변경하고 싶을 수도 있다. 이런 상황에서는 충돌 회피가 실패한다.
일관된 상태 수렴
수렴 충돌 해소를 달성하는 방법
1. 각 쓰기의 고유 ID를 부여하고 가장 높은 ID를 가진 쓰기를 고른다.
2. 각 복제 서버에 고유 ID를 부여하고 높은 숫자의 복제 서버에서 생긴 쓰기가 낮은 숫자의 복제 서버에서 갱긴 쓰기보다 항상 우선적으로 적용되게 한다.
3. 어떻게든 값을 병합한다. 사전 순으로 정렬한 후 연결
4. 명시적 데이터 구조에 충돌을 기록해 모든 정보를 보존한다. 나중에 충돌을 해소하는 애플리케이션 코드를 작성한다.
사용자 정의 충동 해소 로직
쓰기 수행 중: 충돌을 감지하자 마자 충돌 핸들러 호출. 백그라운드 프로세스에서 빠르게 실행
일기 수행 중: 충돌을 감지하면 모든 쓰기를 저장.
다중 리더 복제 토폴로지
복제 토폴로지는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명한다.
리더 없는 복제
관계형 데이터베이스가 우세한 시대에는 대부분 잊혀졌다. 아마존이 내부 다이나모 시스템에서 사용한 후 다시 데이터베이스용 아키텍처로 유행했다. 리악, 카산드라, 볼드모트는 다이나모 스타일이라 한다.
노드가 다운됐을 때 데이터베이스에 쓰기
리더 없는 설정에서는 장애 복구가 필요하지 않다. 클라이언트가 쓰기를 세 개의 모든 복제 서버에 병렬로 전송한다. 다운된 노드는 쓰기가 누락이 됐을텐데 이를 해결하기 위핸 클라이언트가 데이터베이스에서 읽을 때 하나의 복제 서버로 요청을 보내지 않고 읽기 요청을 병렬로 여러 노드에 전송한다.
읽기 복구와 안티 에트로피
누락된 쓰기 복구 방법
읽기 복구: 클라이언트가 병렬로 읽기를 수행하면 오래된 응답을 감지할 수 있다. 클라이언트는 오래된 값이라는 사실을 알고 해당 복제 서버에 새로운 값을 다시 기록한다. 이 접근 방식은 자주 읽는 상황에서 적합하다.
안티 엔트로피 처리: 추가적으로 일부 데이터스토어는 백그라우느 프로세스를 두고 복제 서버 간 데이터 차이를 지속적으로 찾아 누락된 데이터를 하나의 복제 서버에서 다른 서버로 복사한다. 안티 엔트로피 처리는 특성 순서로 쓰기를 복사하기 때문에 데이터가 복사되기까지 상당한 지연이 있을 수 있다.
읽기와 쓰기를 위한 정족수
노드 개수는 홀수, 쓰기와 읽기는 과반수.
상황에 따라 설정 가능. 쓰기가 적고 읽기가 많은 경우 w=n, r=1이 좋다. 읽기는 빨라지지만 노드 하나가 고장나면 모든 데이터베이스 쓰기가 실패한다.
동시 쓰기 감지
다이나모 스타일 데이터베이스는 여러 클라이언트가 동시에 같은 키에 쓰는 것을 허용하기 때문에 엄격한 정족수를 사용하더라도 충돌이 발생한다.
최종적인 일관성을 달성하기 위해 복제본들은 동일한 값이 돼야 한다.
최종 쓰기 승리(동시 쓰기 버리기)
최종적으로 값을 수혐하기 위한 접근 방식 하나는 각 복제본이 가진 예전 값을 버리고 최신 값을오 덮어쓰는 방법이다.
'Software Development > Database' 카테고리의 다른 글
[데이터 중심 애플리케이션] 트랜잭션 (0) 2021.11.07 [데이터 중심 애플리케이션] 파티셔닝(분산 데이터) (0) 2021.10.31 [데이터 중심 애플리케이션] 저장소와 검색 (0) 2021.09.05 [MongoDB] 몽고디비 정리 (0) 2021.07.07 [Oracle] 오라클 - Function 생성 및 실행 방법 (0) 2020.10.15