책너두 (데이터 중심 애플리케이션 설계) 13일차 (~162p)

요약

  • 2장 분산 데이터에 대해 알게 됨
  • 고부하로의 확장이 필요함.
    • 복제와 파티셔닝이 필요함.
    • 복제의 경우 리더와 팔로워간 복제 서버를 의미함.
  • 동기식, 비동기식 복제 여부를 알게 됨.
  • 노드 중단 처리에 대한 내용을 이해하게 됨.
    • 팔로워 장애
      • 복구 쉬움
    • 리더 장애
      • 복구 까다로움
  • 복제 로그 구현 방식에 대해 알게 됨.
    • 구문 기반 복제
      • 구문을 쓰고, 팔로워에게 전달
    • 쓰기 전 로그 배송
      • 리더에 쓰기 전 로그 배송하여 팔로워가 먼저 업데이트 됨 → 중단 시간 없이 장애 복구 가능
    • 트리거 기반 복제
      • 애플리케이션 코드로 데이터베이스의 데이터 변경시 트리거가 발생하여 코드가 실행되면서 복제

메모

Part2 분산 데이터

  • 2부에서는 저장소와 데이터 검색에 여러 장비가 관여할때 발생하는 일에 대해 알아본다.
  • 여러 장비 간 분산된 데이터베이스를 필요로 하는 이유는 여러가지임.
    • 확장성
      • 데이터의 양을 분배하여 단일 장비보다 부하를 여러 장비로 분배할 수 있음.
    • 내결함성/고가용성
      • 장비 하나가 죽어도 다른 장비가 이어 받는다.
    • 지연 시간
      • 전 세계의 사용자가 있다면, 지리적으로 가까운 데이터센터에서 서비스 제공하는 것이 더 빠름.

고부하로 확장

  • 고부하 확장이 필요한 경우, 더 강력한 장비를 구매하는 것이 가장 간단한 방법임
    • = 수직 확장 or 용량 확장
    • 많은 CPU, 많은 메모리 칩, 많은 디스크를 하나의 운영체제로 함께 결합할 수 있음.
    • 공유 메모리 아키텍처(shared-memory architecture)에서 모든 구성 요소를 단일 장비처럼 다룰 수 있음.
      • 공유 메모리 접근 방식의 문제점
        • 비용이 선형적인 추세보다 훨씬 빠르게 증가함.
        • 병목 현상 때문에 두 배 크기의 장비가 반드시 두 배의 부하를 처리할 수 있는게 아님.
      • 공유 메모리 아키텍처는 제한적인 내결함성을 제공함.
        • ex) 하이엔드 장비의 핫 스왑 이용 (핫 스왑 가능 → 장비를 중단시키지 않고 디스크, 메모리 모듈, CPU도 교체할 수 있음.)
        • 하지만 완전히 하나의 지리적인 위치로 제한됨.
    • 다른 접근 방식으로 공유 디스크 아키텍처가 있음.
      • 독립적인 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 복제 지연 문제에서 다시 설명)

체인 복제를 이용하여 데이터 유실이 없는 방법을 지속적으로 연구하는 중임.

새로운 팔로워 설정

  • 복제 서버 수를 늘리거나 장애 노드의 대체를 위해 새로운 팔로워를 설정해야 함.
    • 단순히 한 노드에서 다른 노드로 데이터 파일을 복사하는 것만으로는 충분하지 않음.
      • 표준 파일 복사본이 다른 시점의 데이터베이스의 다른 부분을 볼 수 있기 때문에 복사 결과가 유효하지 않을 수 있음.
    • 데이터베이스를 잠궈서(쓰기가 불가능하게 만듦) 디스크 파일의 일관성을 만들 수 있지만, 고가용성 목표에 부합하지 않음.
  • 팔로워 설정은 다행히 대체적으로 중단 시간없이 수행할 수 있음.
  • 아래는 팔로워 설정에 대한 과정임
    1. 전체 데이터베이를 잠그지 않고 리더의 데이터베이스 스냅샷을 일정 시점에 가져옴.
    2. 스냅샷을 새로운 팔로워 노드에 복사함.
    3. 팔로워는 리더에 연결해 스냅샷 이후에 발생한 모든 데이터 변경을 요청함.
      • 여기서 스냅샷은 리더의 복제 로그의 정확한 위치와 연관돼야 함.
      • 이 위치는 로그 일련번호(postgresql)라고도 하고 이진로그 좌표(mysql)라고도 부름.
    • 팔로워가 스냅샷 이후 데이터 변경의 미처리분(backlog)을 모두 처리했을 때 따라잡았다고 말함.
  • 팔로워 설정하는 실제 과정은 데이터베이스에 따라 다름.

노드 중단 처리

  • 장애로 인해 시스템의 모든 노드가 예기치 않게 중단될 수 있음.
  • 계획된 유지보수(ex: 커널의 보안패치 설치를 위한 장비 리부팅)로 인해 중단될 수도 있음.
  • 개별 노드의 장애에도 전체 시스템이 동작하게끔 유지하고, 노드 중단의 영향을 최소화하는 것이 목표임.

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

  • 각 팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관함.
  • 팔로워가 죽어서 재시작하거나 리더와 팔로워 사이 네트워크가 일시 중단되면, 팔로워는 쉽게 복구 가능함.
    1. 보관된 로그에서 결함이 발생하기 전 처리한 마지막 트랜잭션을 알아냄
    2. 팔로워는 리더에 연결해 팔로워 연결이 끊어진 동안 발생한 데이터 변경을 모두 요청할 수 있음.

리더 장애: 장애 복구

  • 리더의 장애 처리는 까다로움
    • 팔로워 중 하나를 새로운 리더로 승격해야 함
    • 클라이언트는 새로운 리더로 쓰기를 전송하기 위해 재설정이 필요함
    • 다른 팔로워는 새로운 리더로부터 데이터 변경을 소비하기 시작해야 함
      • 위 과정을 장애 복구(failover) 라고 함.
  • 장애 복구는 수동으로 진행하거나 자동으로 진행함.
  • 자동 장애 복구는 보통 다음과 같은 단계로 구성됨
    • 리더가 장애인지 판단함
      • 무엇이 잘못됐는지 발견할 확실한 방법이 없기에 대부분의 시스템은 단순히 타임아웃을 사용함.
      • ex) 타임아웃, 30초 동안 노드 응답이 없으면 죽은 것으로 간주함.
    • 새로운 리더를 선택함.
      • 새로운 리더로 가장 적합한 후보는 이전 리더의 최신 데이터 변경사항을 가진 복제 서버임.
    • 새로운 리더 사용을 위해 시스템을 재설정한다.
      • 클라이언트는 새로운 쓰기 요청을 새로운 리더에 보내야 함.
      • 요청 라우팅을 설정해야함.
  • 장애 복구 과정을 잘못될 가능성이 높음.
    • 비동기식 복제 시, 새로운 리더는 이전 리더가 실패하기 전의 쓰기를 일부 수신하지 못할 수 있음.
      • 가장 일반적인 해결책은 이전 리더의 복제되지 않은 쓰기를 단순히 폐기하는 방법임
      • 이는, 클라이언트에 대한 신뢰를 저버림.
        • ex) 유효하지 않은 MySQL 팔로워가 리더로 승격된 경우, 이 리더는 예전 리더보다 뒤쳐진 상황인데, 이전 리더가 예전에 할당한 기본 키를 재사용함. 그리고 이 기본 키는 레디스에 저장에도 사용되었기에, 데이터 불일치가 발생함.
    • 두 노드가 모두 자신이 리더라고 믿는 상황이 있음 (8장 참고)
      • 위 상황을 스플릿 브레인(split brain) 이라고 함.
      • 두 리더가 쓰기를 받으면서 충돌을 해소하지 않으면 데이터 유실이 발생하거나 오염됨.
    • 리더가 죽었다고 판단 하는 타임아웃이 길면 복구까지 오랜 시간이 소요된다는 뜻임.
      • 타임아웃이 너무 짧으면 불필요한 장애 복구가 있을 수 있음.
        • ex) 일시적인 부하급증으로 노드의 응답 시간이 타임아웃보다 커지거나 네트워크 고장으로 패킷이 지연되는 경우
  • 위 문제에 대한 쉬운 해결책은 없음.
  • 이 문제 때문에 일부 운영팀은 소프트웨어가 자동 장애 복구를 지원하더라도 수동으로 장애 복구를 수행하는 방식을 선호함.

복제 로그 구현

  • 리더 기반 복제는 다양한 방법을 사용함.

구문 기반 복제

  • 리더는 모든 쓰기 요청(구문 = statement)을 기록하고 쓰기를 실행한 다음, 구문 로그를 팔로워에게 전송한다.
    • 관계형 데이터베이스는 모든 INSERT, UPDATE, DELETE 구문을 팔로워에게 전달하고 각 팔로워는 클라이언트에서 직접 받은 것처럼 SQL 구문을 파싱하고 실행함.
    • 이 접근은 복제가 깨질 수 있는 다양한 사례가 있음.
      • 현재 시간 NOW(), 임의 숫자 RAND() → 비결정적 함수를 호출하는 구문은 복제 서버마다 다른 값을 생성할 가능성이 있음.
      • 자동 증가 칼럼을 사용하는 구문은 각 복제 서버에서 정확히 같은 순서로 실행돼야 함.
      • 부수 효과를 가진 구문(ex: 트리거, 스토어드 프로시저, 사용자 정의 함수)는 완벽하게 결정적이지 않으면 각 복제 서버에서 다른 부수 효과를 발생할 수 있음.
    • 위 문제들은 대안 해결책이 있음.
      • ex) 리더가 구문을 기록할 때 모든 비결정적 함수 호출을 고정 값을 반환하게끔 대체 할 수 있음.
        • 이 방식도 여러 에지 케이스가 있기에, 일반적으로 다른 복제 방법을 선호함.
      • MySQL 5.1 이전 버전에서 구문 기반 복제가 사용됨.
        • 매우 간편해서 오늘날에도 사용됨.
        • 하지만 MySQL은 이제 구문에 비결정성이 있다면 기본적으로 로우 기반 복제로 변경함.

쓰기 전 로그 배송

  • 일반적으로 모든 쓰기는 로그에 기록함.
    • 로그 구조화 저장소 엔진의 경우, 로그 자체가 저장소의 주요 부분임.
      • 로그 세그먼트는 작게 유지되고, 백그라운드로 가비지 컬렉션함.
    • 개별 디스크 블록에 덮어쓰는 B 트리
      • 모든 변경을 쓰기 전 로그에 쓰기 때문에 고장 이후 일관성 있는 상태로 색인을 복원할 수 있음.
  • 위 두 경우 모두 로그는 데이터베이스의 모든 쓰기를 포함한 추가 전용 바이트 열임.
    • 완전히 동일한 로그를 사용해서 다른 노드에서 복제 서버를 구축할 수 있음.
    • 리더는 디스크에 로그를 기록하는 일 외에 팔로워에게 네트워크로 로그를 전송하기도 함.
  • 로그의 가장 큰 단점은 제일 저수준의 데이터를 기술한다는 점임
    • WAL은 어떤 디스크 블록에서 어떤 바이트를 변경했는지와 같은 상세 정보를 포함함
    • 이는 복제가 저장소 엔진과 밀접하게 엮임
    • 따라서, 저장소 형식이 다른 버전으로 바뀌면, 해당 로그를 실행할 수 없을 수 있음.
      • 이 문제는 새로운 소프트웨어 버전을 팔로워가 먼저 사용하게끔 복제 프로토콜을 허용한다면, 중단시간 없이 데이터베이스 소프트웨어 업그레이드 수행이 가능함.

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

  • 복제 로그를 저장소 엔진 내부와 분리하기 위한 대안 중 하나로, 복제와 저장소 엔진을 위해 다른 로그 형식을 사용하는 것임.
    • 이 복제 로그를 논리적 로그(logical log)라고 부름
    • 관계형 데이터베이스용 논리적 로그는 로우 단위로 데이터베이스 테이블에 쓰기를 기술한 레코드 열임.
    • 여러 로우를 수정하는 트랜잭션은 여러 로그 레코드를 생성하고, 트랜잭션이 커밋됐음을 레코드에 표시함.
      • 논리적 로그를 저장소 엔진 내부와 분리했으므로 하위 호환성을 쉽게 유지할 수 있음.
      • 리더와 팔로워에서 다른 버전의 데이터베이스 소프트웨어나, 다른 저장소 엔진을 실행할 수 있음.
      • 이 논리적 로그 형식은 외부 애플리케이션이 파싱하기 쉬움
        • 오프라인 분석, 사용자 정의 색인, 캐시 구축을 위한 데이터 웨어하우스 같이, 외부 시스템으로 내용을 전송하고자 할 때 유용함.
          • 이를 변경 데이터 캡처라고 부름(11장에서 설명)

트리거 기반 복제

  • 지금까지 설명한 복제 접근 방식은 애플리케이션 코드 사용 없이 데이터베이스 시스템에서 구현됨.
    • 이 방식은 유연성이 필요한 몇 가지 상황이 있음.
      • 데이터의 서브셋만 복제한 경우
      • 데이터베이스를 다른 종류의 데이터베이스로 복제해야 하는 경우
      • 충돌 해소 로직이 필요한 경우
        • 위 경우, 복제를 애플리케이션 층으로 옮겨야 함.
  • 많은 관계형 데이터베이스에서 사용할 수 있는 기능인 트리거스토어드 프로시저를 사용해서 애플리케이션에서 처리할 수 있음.
    • 트리거는 사용자 정의 애플리케이션 코드를 등록할 수 있게 함.
      • 데이터베이스 시스템에서 데이터 변경되면 자동으로 애플리케이션 코드가 실행됨.
  • 일반적으로 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있음.
    • 이는 버그나 제한 사항도 더 많이 발생함.
    • 그럼에도, 트리거 기반 복제는 유연성 때문에 매우 유용함.

댓글

Designed by JB FACTORY