책너두 (데이터 중심 애플리케이션 설계) 13일차 (~162p)
- Book/데이터 중심 애플리케이션 설계
- 2023. 3. 29.
요약
- 2장 분산 데이터에 대해 알게 됨
- 고부하로의 확장이 필요함.
- 복제와 파티셔닝이 필요함.
- 복제의 경우 리더와 팔로워간 복제 서버를 의미함.
- 동기식, 비동기식 복제 여부를 알게 됨.
- 노드 중단 처리에 대한 내용을 이해하게 됨.
- 팔로워 장애
- 복구 쉬움
- 리더 장애
- 복구 까다로움
- 팔로워 장애
- 복제 로그 구현 방식에 대해 알게 됨.
- 구문 기반 복제
- 구문을 쓰고, 팔로워에게 전달
- 쓰기 전 로그 배송
- 리더에 쓰기 전 로그 배송하여 팔로워가 먼저 업데이트 됨 → 중단 시간 없이 장애 복구 가능
- 트리거 기반 복제
- 애플리케이션 코드로 데이터베이스의 데이터 변경시 트리거가 발생하여 코드가 실행되면서 복제
- 구문 기반 복제
메모
Part2 분산 데이터
- 2부에서는 저장소와 데이터 검색에 여러 장비가 관여할때 발생하는 일에 대해 알아본다.
- 여러 장비 간 분산된 데이터베이스를 필요로 하는 이유는 여러가지임.
- 확장성
- 데이터의 양을 분배하여 단일 장비보다 부하를 여러 장비로 분배할 수 있음.
- 내결함성/고가용성
- 장비 하나가 죽어도 다른 장비가 이어 받는다.
- 지연 시간
- 전 세계의 사용자가 있다면, 지리적으로 가까운 데이터센터에서 서비스 제공하는 것이 더 빠름.
- 확장성
고부하로 확장
- 고부하 확장이 필요한 경우, 더 강력한 장비를 구매하는 것이 가장 간단한 방법임
- = 수직 확장 or 용량 확장
- 많은 CPU, 많은 메모리 칩, 많은 디스크를 하나의 운영체제로 함께 결합할 수 있음.
- → 공유 메모리 아키텍처(shared-memory architecture)에서 모든 구성 요소를 단일 장비처럼 다룰 수 있음.
- 공유 메모리 접근 방식의 문제점
- 비용이 선형적인 추세보다 훨씬 빠르게 증가함.
- 병목 현상 때문에 두 배 크기의 장비가 반드시 두 배의 부하를 처리할 수 있는게 아님.
- 공유 메모리 아키텍처는 제한적인 내결함성을 제공함.
- ex) 하이엔드 장비의 핫 스왑 이용 (핫 스왑 가능 → 장비를 중단시키지 않고 디스크, 메모리 모듈, CPU도 교체할 수 있음.)
- 하지만 완전히 하나의 지리적인 위치로 제한됨.
- 공유 메모리 접근 방식의 문제점
- 다른 접근 방식으로 공유 디스크 아키텍처가 있음.
- 독립적인 CPU, RAM을 탑재한 여러 장비를 사용함.
- 데이터 저장은 장비 간 공유하는 디스크 배열에 함.
- 여러 장비는 고속 네트워크로 연결됨.
- 일부 데이터 웨어하우슨 작업부하에 이 아키텍처를 사용함.
- 하지만 잠금 경합과 오버헤드가 공유 디스크 접근 방식의 확장성을 제한함.
- 독립적인 CPU, RAM을 탑재한 여러 장비를 사용함.
비공유 아키텍처
- 비공유 아키텍처(shared-nothing)
- = 수평 확장 or 규모확장
- 이 접근 방식에서, 데이터베이스 소프트웨어를 수행하는 각 장비나 가상 장비를
노드
라고 부름- 각 노드는 CPU, RAM, 디스크를 독립적으로 사용함.
- 노드간 코디네이션은 일반적인 네트워크를 사용하여 소프트웨어 수준에서 수행함.
- 특별한 하드웨어를 필요로 하지 않음.
- 가격 대비 성능이 가장 좋은 시스템을 사용할 수 있음.
- 잠재적으로 여러 지리적인 영역에 걸쳐 데이터를 분산해 사용자 지연 시간을 줄임 → 전체 데이터센터의 손실을 줄일 수 있음.
- 비공유 아키텍처를 사용할 애플리케이션 개발자는 반드시 주의해야할 점이 있음.
- 데이터를 여러 노드에 분산하려면 분산 시스템에서 발생하는 제약 조건과 트레이드오프를 알고 있어야 함.
- 분산 비공유 아키텍처는 많은 장점이 있지만, 부가적으로 애플리케이션 복잡도를 야기하고 때로, 사용할 수 있는 데이터 모델의 표현을 제한함.
복제 대 파티셔닝
- 여러 노드에 데이터를 분산하는 방법은 일반적으로 두 가지가 있음.
- 복제
- 같은 데이터의 복사본을 잠재적으로 다른 위치에 있는 여러 노드에 유지함.
- 중복성을 제공함.
- 일부 노드가 사용 불가 상태면, 해당 데이터는 남은 다른 노드를 통해 여전히 제공할 수 있음.
- 성능 향상에 도움이 됨.
- 파티셔닝
- 큰 데이터베이스를 파티션이라는 작은 서브셋으로 나눔.
- 각 파티션은 각기 다른 노드에 할당함(샤딩이라고 함.)
- 복제
- 복제와 파티셔닝 개념을 이해하면, 분산 시스템에서 필요한 어려운 트레이드오프를 설명할 수 있음.
5장. 복제
- 복제란 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지한다는 의미
- 5장에서는 데이터셋이 아주 작아, 각 장비에 전체 데이터셋의 복사본을 보유할 수 있다고 가정함.
- 6장에서는 단일 장비에 넣기 너무 큰 데이터셋을 대상으로한 파티셔닝(샤딩)을 살펴본다.
- 복제의 어려운 점은 데이터의 변경에 대한 처리임.
- 노드 간 변경을 복제하기 위한 세 가지 인기 있는 알고리즘을 살펴본다.
- 단일 리더(single-leader)
- 다중 리더(multi-leader)
- 리더 없는(leaderless)
- 거의 모든 분산 데이터베이스는 이 세 가지 방법 중 하나를 사용함.
- 노드 간 변경을 복제하기 위한 세 가지 인기 있는 알고리즘을 살펴본다.
- 복제에는 고려해야할 트레이드오프가 있음.
- 동기식 복제와 비동기식 복제 중 어떤 것을 사용할 것인가
- 잘못된 복제본을 어떻게 처리할 것인가
- 이 트레이드오프는 대개 데이터베이스의 설정 옵션임.
- 세부 사항은 데이터베이스마다 다양하더라도, 일반적인 원리는 다양한 구현간에도 유사함.
- 데이터베이스 복제는 오래된 주제임.
- 하지만 많은 개발자들은 오랫동안 여전히 단일 노드로만 구성된 데이터베이스를 가정함.
- 분산 데이터베이스의 주된 사용은 최근임.
리더와 팔로워
- 데이터베이스 복사본을 저장하는 각 노드를 복제 서버(replica) 라고 함.
- 모든 복제 서버에 모든 데이터가 있다는 사실을 어떻게 보장하는가?
- 데이터베이스의 모든 쓰기는 모든 복제 서버에서 처리돼야 함.
- 리더 기반 복제(leader-based replication)를 해야 함(= 능동(active)/수동(passive), 마스터(master)/슬레이브(slave) 복제라고도 함.)
- 복제 서버 중 하나를 리더(leader = 마스터나 프라이머리 라고도 함)로 지정한다.
- 클라이언트가 데이터베이스에 쓰기를 할 때, 클라이언트는 요청을 리더에게 보내야 함.
- 다른 복제 서버는 팔로워(follower = 읽기 복제 서버(read replica, 슬레이브, 2차(secondary), 핫 대기(hot standby)) 라고 함.
- 리더가 로컬 저장소에 새로운 데이터를 기록할 때마다 데이터 변경을 복제 로그(replication log)나 변경 스트림(change strea)의 일부로 팔로워에게 전송함.
- 각 팔로워가 리더로부터 로그를 받으면 리더가 처리한 것과 동일한 순서로 모든 쓰기를 적용해서 그에 맞게 데이터베이스의 로컬 복사본을 갱신함.
- 클라이언트가 데이터베이스로부터 읽기를 할 때는 리더, 또는 임의 팔로워에게 질의 가능함.
- 하지만 쓰기를 리더에게만 허용함.
- 데이터베이스의 모든 쓰기는 모든 복제 서버에서 처리돼야 함.
- 위 복제 모드는 여러 관계형 데이터베이스에 내장된 기능이며, 일부 비관계형 데이터베이스에도 사용함.
- 리더 기반 복제는 데이터베이스에만 국한되지 않음
- 카프카, 래빗MQ, 고가용성 큐 같은 분산 메시지 브로커에도 사용됨.
- 일부 네트워크 파일 시스템과 DRBD 같은 복제 블럭 디바이스도 유사함.
- 리더 기반 복제는 데이터베이스에만 국한되지 않음
- 모든 복제 서버에 모든 데이터가 있다는 사실을 어떻게 보장하는가?
동기식 대 비동기식 복제
- 복제 시스템의 중요 세부 사항은 복제가 동기식, 혹은 비동기식으로 발생하는지 여부임.
- 리더에 쓰기가 발생하면, 리더는 팔로워에게 데이터 변경 로그를 보내고, 팔로워가 확인해서 쓰기 동기화가 끝날 때까지 성공을 기다리는 방식이 동기식임.
- 팔로워가 리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장함.
- 동기 팔로워가 죽거나 네트워크 문제 등 다른 어떤 이유로 인해 응답하지 않으면 쓰기가 처리될 수 없음.
- 리더는 모든 쓰기를 차단(block)하고 동기 복제 서버가 다시 사용할 수 있을 때 까지 기다려야 함.
- 이와 반대로, 리더가 쓰기를 통해 데이터 변경 로그를 팔로워에게 보내고, 팔로워 응답을 기다리지 않는 방식이 비동기식임.
- 팔로워가 장애를 복구 중이거나 시스템이 최대 가용량 부근에서 동작하거나, 노드 간 네트워크 문제가 있을 경우, 팔로워가 리더와 멀어질 수 있음.
- 리더에 쓰기가 발생하면, 리더는 팔로워에게 데이터 변경 로그를 보내고, 팔로워가 확인해서 쓰기 동기화가 끝날 때까지 성공을 기다리는 방식이 동기식임.
- 모든 팔로워가 동기식인 상황은 비현실적임.
- 임의 한 노드의 장애는 전체 시스템을 멈추게 하기 때문.
- 현실적으로 데이터베이스에서 동기식 복제를 사용하려면, 보통 팔로워 하나는 동기식, 나머지는 비동기식으로 해야 함.
- 적어도 두 노드에 데이터의 최신 복사본이 있는 것을 보장함
- 이를 반동기식(semi-synchronous) 라고 함.
- 보통, 리더 기반 복제는 완전히 비동기식으로 구성함.
- 리더가 잘못되어 복구할 수 없으면 팔로워에 모든 쓰기가 유실됨.
- 그럼에도 많은 팔로워가 있거나 지리적으로 분산된 경우 비동기식 복제를 널리 사용함(p161 복제 지연 문제에서 다시 설명)
체인 복제를 이용하여 데이터 유실이 없는 방법을 지속적으로 연구하는 중임.
새로운 팔로워 설정
- 복제 서버 수를 늘리거나 장애 노드의 대체를 위해 새로운 팔로워를 설정해야 함.
- 단순히 한 노드에서 다른 노드로 데이터 파일을 복사하는 것만으로는 충분하지 않음.
- 표준 파일 복사본이 다른 시점의 데이터베이스의 다른 부분을 볼 수 있기 때문에 복사 결과가 유효하지 않을 수 있음.
- 데이터베이스를 잠궈서(쓰기가 불가능하게 만듦) 디스크 파일의 일관성을 만들 수 있지만, 고가용성 목표에 부합하지 않음.
- 단순히 한 노드에서 다른 노드로 데이터 파일을 복사하는 것만으로는 충분하지 않음.
- 팔로워 설정은 다행히 대체적으로 중단 시간없이 수행할 수 있음.
- 아래는 팔로워 설정에 대한 과정임
- 전체 데이터베이를 잠그지 않고 리더의 데이터베이스 스냅샷을 일정 시점에 가져옴.
- 스냅샷을 새로운 팔로워 노드에 복사함.
- 팔로워는 리더에 연결해 스냅샷 이후에 발생한 모든 데이터 변경을 요청함.
- 여기서 스냅샷은 리더의 복제 로그의 정확한 위치와 연관돼야 함.
- 이 위치는 로그 일련번호(postgresql)라고도 하고 이진로그 좌표(mysql)라고도 부름.
- 팔로워가 스냅샷 이후 데이터 변경의 미처리분(backlog)을 모두 처리했을 때 따라잡았다고 말함.
- 팔로워 설정하는 실제 과정은 데이터베이스에 따라 다름.
노드 중단 처리
- 장애로 인해 시스템의 모든 노드가 예기치 않게 중단될 수 있음.
- 계획된 유지보수(ex: 커널의 보안패치 설치를 위한 장비 리부팅)로 인해 중단될 수도 있음.
- 개별 노드의 장애에도 전체 시스템이 동작하게끔 유지하고, 노드 중단의 영향을 최소화하는 것이 목표임.
팔로워 장애: 따라잡기 복구
- 각 팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관함.
- 팔로워가 죽어서 재시작하거나 리더와 팔로워 사이 네트워크가 일시 중단되면, 팔로워는 쉽게 복구 가능함.
- 보관된 로그에서 결함이 발생하기 전 처리한 마지막 트랜잭션을 알아냄
- 팔로워는 리더에 연결해 팔로워 연결이 끊어진 동안 발생한 데이터 변경을 모두 요청할 수 있음.
리더 장애: 장애 복구
- 리더의 장애 처리는 까다로움
- 팔로워 중 하나를 새로운 리더로 승격해야 함
- 클라이언트는 새로운 리더로 쓰기를 전송하기 위해 재설정이 필요함
- 다른 팔로워는 새로운 리더로부터 데이터 변경을 소비하기 시작해야 함
- 위 과정을 장애 복구(failover) 라고 함.
- 장애 복구는 수동으로 진행하거나 자동으로 진행함.
- 자동 장애 복구는 보통 다음과 같은 단계로 구성됨
- 리더가 장애인지 판단함
- 무엇이 잘못됐는지 발견할 확실한 방법이 없기에 대부분의 시스템은 단순히 타임아웃을 사용함.
- ex) 타임아웃, 30초 동안 노드 응답이 없으면 죽은 것으로 간주함.
- 새로운 리더를 선택함.
- 새로운 리더로 가장 적합한 후보는 이전 리더의 최신 데이터 변경사항을 가진 복제 서버임.
- 새로운 리더 사용을 위해 시스템을 재설정한다.
- 클라이언트는 새로운 쓰기 요청을 새로운 리더에 보내야 함.
- 요청 라우팅을 설정해야함.
- 리더가 장애인지 판단함
- 장애 복구 과정을 잘못될 가능성이 높음.
- 비동기식 복제 시, 새로운 리더는 이전 리더가 실패하기 전의 쓰기를 일부 수신하지 못할 수 있음.
- 가장 일반적인 해결책은 이전 리더의 복제되지 않은 쓰기를 단순히 폐기하는 방법임
- 이는, 클라이언트에 대한 신뢰를 저버림.
- ex) 유효하지 않은 MySQL 팔로워가 리더로 승격된 경우, 이 리더는 예전 리더보다 뒤쳐진 상황인데, 이전 리더가 예전에 할당한 기본 키를 재사용함. 그리고 이 기본 키는 레디스에 저장에도 사용되었기에, 데이터 불일치가 발생함.
- 두 노드가 모두 자신이 리더라고 믿는 상황이 있음 (8장 참고)
- 위 상황을 스플릿 브레인(split brain) 이라고 함.
- 두 리더가 쓰기를 받으면서 충돌을 해소하지 않으면 데이터 유실이 발생하거나 오염됨.
- 리더가 죽었다고 판단 하는 타임아웃이 길면 복구까지 오랜 시간이 소요된다는 뜻임.
- 타임아웃이 너무 짧으면 불필요한 장애 복구가 있을 수 있음.
- ex) 일시적인 부하급증으로 노드의 응답 시간이 타임아웃보다 커지거나 네트워크 고장으로 패킷이 지연되는 경우
- 타임아웃이 너무 짧으면 불필요한 장애 복구가 있을 수 있음.
- 비동기식 복제 시, 새로운 리더는 이전 리더가 실패하기 전의 쓰기를 일부 수신하지 못할 수 있음.
- 위 문제에 대한 쉬운 해결책은 없음.
- 이 문제 때문에 일부 운영팀은 소프트웨어가 자동 장애 복구를 지원하더라도 수동으로 장애 복구를 수행하는 방식을 선호함.
복제 로그 구현
- 리더 기반 복제는 다양한 방법을 사용함.
구문 기반 복제
- 리더는 모든 쓰기 요청(구문 = statement)을 기록하고 쓰기를 실행한 다음, 구문 로그를 팔로워에게 전송한다.
- 관계형 데이터베이스는 모든 INSERT, UPDATE, DELETE 구문을 팔로워에게 전달하고 각 팔로워는 클라이언트에서 직접 받은 것처럼 SQL 구문을 파싱하고 실행함.
- 이 접근은 복제가 깨질 수 있는 다양한 사례가 있음.
- 현재 시간 NOW(), 임의 숫자 RAND() → 비결정적 함수를 호출하는 구문은 복제 서버마다 다른 값을 생성할 가능성이 있음.
- 자동 증가 칼럼을 사용하는 구문은 각 복제 서버에서 정확히 같은 순서로 실행돼야 함.
- 부수 효과를 가진 구문(ex: 트리거, 스토어드 프로시저, 사용자 정의 함수)는 완벽하게 결정적이지 않으면 각 복제 서버에서 다른 부수 효과를 발생할 수 있음.
- 위 문제들은 대안 해결책이 있음.
- ex) 리더가 구문을 기록할 때 모든 비결정적 함수 호출을 고정 값을 반환하게끔 대체 할 수 있음.
- 이 방식도 여러 에지 케이스가 있기에, 일반적으로 다른 복제 방법을 선호함.
- MySQL 5.1 이전 버전에서 구문 기반 복제가 사용됨.
- 매우 간편해서 오늘날에도 사용됨.
- 하지만 MySQL은 이제 구문에 비결정성이 있다면 기본적으로 로우 기반 복제로 변경함.
- ex) 리더가 구문을 기록할 때 모든 비결정적 함수 호출을 고정 값을 반환하게끔 대체 할 수 있음.
쓰기 전 로그 배송
- 일반적으로 모든 쓰기는 로그에 기록함.
- 로그 구조화 저장소 엔진의 경우, 로그 자체가 저장소의 주요 부분임.
- 로그 세그먼트는 작게 유지되고, 백그라운드로 가비지 컬렉션함.
- 개별 디스크 블록에 덮어쓰는 B 트리
- 모든 변경을 쓰기 전 로그에 쓰기 때문에 고장 이후 일관성 있는 상태로 색인을 복원할 수 있음.
- 로그 구조화 저장소 엔진의 경우, 로그 자체가 저장소의 주요 부분임.
- 위 두 경우 모두 로그는 데이터베이스의 모든 쓰기를 포함한 추가 전용 바이트 열임.
- 완전히 동일한 로그를 사용해서 다른 노드에서 복제 서버를 구축할 수 있음.
- 리더는 디스크에 로그를 기록하는 일 외에 팔로워에게 네트워크로 로그를 전송하기도 함.
- 로그의 가장 큰 단점은 제일 저수준의 데이터를 기술한다는 점임
- WAL은 어떤 디스크 블록에서 어떤 바이트를 변경했는지와 같은 상세 정보를 포함함
- 이는 복제가 저장소 엔진과 밀접하게 엮임
- 따라서, 저장소 형식이 다른 버전으로 바뀌면, 해당 로그를 실행할 수 없을 수 있음.
- 이 문제는 새로운 소프트웨어 버전을 팔로워가 먼저 사용하게끔 복제 프로토콜을 허용한다면, 중단시간 없이 데이터베이스 소프트웨어 업그레이드 수행이 가능함.
논리적(로우 기반) 로그 복제
- 복제 로그를 저장소 엔진 내부와 분리하기 위한 대안 중 하나로, 복제와 저장소 엔진을 위해 다른 로그 형식을 사용하는 것임.
- 이 복제 로그를 논리적 로그(logical log)라고 부름
- 관계형 데이터베이스용 논리적 로그는 로우 단위로 데이터베이스 테이블에 쓰기를 기술한 레코드 열임.
- 여러 로우를 수정하는 트랜잭션은 여러 로그 레코드를 생성하고, 트랜잭션이 커밋됐음을 레코드에 표시함.
- 논리적 로그를 저장소 엔진 내부와 분리했으므로 하위 호환성을 쉽게 유지할 수 있음.
- 리더와 팔로워에서 다른 버전의 데이터베이스 소프트웨어나, 다른 저장소 엔진을 실행할 수 있음.
- 이 논리적 로그 형식은 외부 애플리케이션이 파싱하기 쉬움
- 오프라인 분석, 사용자 정의 색인, 캐시 구축을 위한 데이터 웨어하우스 같이, 외부 시스템으로 내용을 전송하고자 할 때 유용함.
- 이를 변경 데이터 캡처라고 부름(11장에서 설명)
- 오프라인 분석, 사용자 정의 색인, 캐시 구축을 위한 데이터 웨어하우스 같이, 외부 시스템으로 내용을 전송하고자 할 때 유용함.
트리거 기반 복제
- 지금까지 설명한 복제 접근 방식은 애플리케이션 코드 사용 없이 데이터베이스 시스템에서 구현됨.
- 이 방식은 유연성이 필요한 몇 가지 상황이 있음.
- 데이터의 서브셋만 복제한 경우
- 데이터베이스를 다른 종류의 데이터베이스로 복제해야 하는 경우
- 충돌 해소 로직이 필요한 경우
- 위 경우, 복제를 애플리케이션 층으로 옮겨야 함.
- 이 방식은 유연성이 필요한 몇 가지 상황이 있음.
- 많은 관계형 데이터베이스에서 사용할 수 있는 기능인 트리거나 스토어드 프로시저를 사용해서 애플리케이션에서 처리할 수 있음.
- 트리거는 사용자 정의 애플리케이션 코드를 등록할 수 있게 함.
- 데이터베이스 시스템에서 데이터 변경되면 자동으로 애플리케이션 코드가 실행됨.
- 트리거는 사용자 정의 애플리케이션 코드를 등록할 수 있게 함.
- 일반적으로 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있음.
- 이는 버그나 제한 사항도 더 많이 발생함.
- 그럼에도, 트리거 기반 복제는 유연성 때문에 매우 유용함.
'Book > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
책너두 (데이터 중심 애플리케이션 설계) 15일차 (~183p) (0) | 2023.03.31 |
---|---|
책너두 (데이터 중심 애플리케이션 설계) 14일차 (~172p) (0) | 2023.03.30 |
책너두 (데이터 중심 애플리케이션 설계) 12일차 (~147p) (0) | 2023.03.27 |
책너두 (데이터 중심 애플리케이션 설계) 11일차 (~133p) (0) | 2023.03.26 |
책너두 (데이터 중심 애플리케이션 설계) 10일차 (~123p) (0) | 2023.03.25 |