데이터중심 어플리케이션 : 복제

김영상 (dudtkd1221)·2025년 12월 10일

데이터중심 어플리케이션 5장: 복제

복제가 필요한 이유

복제(Replication)는 여러 장비에 동일한 데이터의 복사본을 유지하는 것을 의미하며, 다음과 같은 이점이 있습니다.

  • 지연 시간 감소: 지리적으로 사용자와 가까운 위치에 데이터를 배치하여 네트워크 지연 시간을 줄일 수 있음
  • 가용성 향상: 시스템 일부에 장애가 발생해도 다른 복제 서버를 통해 서비스를 지속적으로 제공 가능
  • 읽기 처리량 증가: 읽기 질의를 처리하는 서버의 수를 늘려 전체 시스템의 처리량을 향상시킬 수 있음

복제의 어려움

복제에서 가장 어려운 문제는 복제된 데이터의 변경을 어떻게 처리할 것인가입니다. 이를 해결하기 위한 세 가지 주요 알고리즘이 있습니다.

  • 단일 리더(Single Leader) 방식
  • 다중 리더(Multi-Leader) 방식
  • 리더 없는(Leaderless) 방식

리더 기반 복제

기본 구조

리더 기반 복제에서는 데이터베이스의 복사본을 저장하는 각 노드를 복제 서버라고 부르며, 두 가지 역할로 구분됩니다.

리더(Leader, Master, Primary)

  • 클라이언트의 모든 쓰기 요청을 받는 서버
  • 쓰기 작업은 오직 리더에만 허용됨
  • 로컬 저장소에 데이터를 기록한 후, 변경 사항을 복제 로그(replication log) 또는 변경 스트림(change stream)을 통해 팔로워에게 전송

팔로워(Follower, Read Replica, Slave, Secondary)

  • 리더로부터 전송받은 데이터 변경사항을 자신의 로컬 저장소에 적용
  • 클라이언트의 읽기 요청을 처리할 수 있음
  • 쓰기는 불가능하며, 리더의 데이터를 복제하는 역할만 수행

동기식 vs 비동기식 복제

동기식 복제(Synchronous Replication)

  • 리더가 쓰기를 확정하기 전에 팔로워가 쓰기를 성공적으로 받았다는 확인을 기다림
  • 장점: 팔로워와 리더가 항상 일관성 있게 최신 데이터 복사본을 가지는 것을 보장
  • 단점: 팔로워가 응답하지 않으면(서버 장애, 네트워크 문제 등) 쓰기 작업이 중단됨
  • 모든 팔로워를 동기식으로 운영하는 것은 비현실적

반동기식 복제(Semi-Synchronous Replication)

  • 팔로워 중 하나는 동기식으로, 나머지는 비동기식으로 운영
  • 동기식 팔로워에 문제가 생기면 다른 비동기식 팔로워를 동기식으로 승격

비동기식 복제(Asynchronous Replication)

  • 리더가 팔로워의 확인을 기다리지 않고 쓰기를 확정
  • 장점: 팔로워에 문제가 생겨도 쓰기 처리를 계속할 수 있음
  • 단점: 리더에 장애가 발생하면 팔로워에 아직 복제되지 않은 쓰기가 모두 유실될 수 있음

새로운 팔로워 설정

장애가 발생한 노드를 대체하거나 복제 서버를 추가할 때, 새로운 팔로워가 리더의 정확한 복제본을 가지도록 하는 과정:

  1. 스냅숏 생성: 특정 시점에 리더의 데이터베이스 스냅숏을 생성
  2. 스냅숏 복사: 생성된 스냅숏을 새로운 팔로워 노드에 복사
  3. 변경사항 동기화: 팔로워가 리더에 연결하여 스냅숏 이후 발생한 모든 데이터 변경을 요청
    • 스냅숏은 리더의 복제 로그의 정확한 위치와 연결되어야 함
    • PostgreSQL: 로그 일련번호(log sequence number)
    • MySQL: 이진로그 좌표(binlog coordinate)
  4. 따라잡기 완료: 팔로워가 스냅숏 이후의 모든 데이터 변경 backlog를 처리하면 동기화 완료

노드 중단 처리 (고가용성 확보)

팔로워 장애 (복구가 비교적 쉬움)

팔로워는 리더로부터 수신한 데이터 변경 로그를 로컬 디스크에 보관하기 때문에:

  1. 보관된 로그에서 장애 발생 직전의 마지막 트랜잭션을 확인
  2. 해당 시점 이후 발생한 데이터 변경사항을 리더에게 요청하여 복구

리더 장애 (복구가 어려움)

리더에 장애가 발생하면 장애 복구(Failover) 과정이 필요합니다.

장애 복구 단계

  1. 리더 장애 판단: 타임아웃 등을 사용하여 리더가 장애 상태인지 확인
  2. 새로운 리더 선출: 팔로워 중 하나를 새로운 리더로 승격
    • 일반적으로 가장 최신 데이터를 가진 팔로워를 선택
  3. 시스템 재설정:
    • 클라이언트가 새로운 리더로 쓰기 요청을 보내도록 재설정
    • 다른 팔로워들이 새로운 리더로부터 데이터 변경을 받도록 설정
    • 이전 리더가 복구되면 팔로워로 전환되도록 처리

복제 로그의 구현 방식

1. 구문 기반 복제(Statement-Based Replication)

모든 쓰기 요청(INSERT, UPDATE, DELETE 등의 SQL 구문)을 기록하고, 구문 로그를 팔로워에게 전송하여 실행하는 방식입니다.

문제점

  • RAND(), NOW() 같은 비결정적 함수는 서버마다 다른 값을 생성
  • UPDATE ... WHERE 등 데이터베이스의 기존 데이터에 의존하는 구문은 실행 순서에 따라 결과가 달라질 수 있음
  • 자동 증가 컬럼이나 트리거가 있는 경우 문제 발생 가능

해결 방법

  • 리더가 비결정적 함수 호출을 고정된 값으로 대체하여 로그에 기록

2. Write-Ahead Log (WAL) Shipping

데이터베이스가 모든 쓰기를 로그에 먼저 기록한 후 실제 데이터를 변경하는 방식을 활용합니다.

  • 리더가 WAL을 팔로워에게 전송
  • 팔로워가 이 로그를 처리하면 리더와 정확히 일치하는 데이터 구조의 복제본 생성

문제점

  • 로그가 저수준의 데이터를 기술하므로 저장소 엔진과 밀접하게 연결됨
  • 데이터베이스 엔진 버전이 변경되면 호환성 문제가 발생할 수 있음
  • 리더와 팔로워가 다른 버전의 소프트웨어를 실행하기 어려움

3. 로우 기반 복제(Row-Based Replication, Logical Log)

복제 로그를 저장소 엔진 내부와 분리하기 위한 방식으로, 물리적 데이터 표현과 구분되는 논리적 로그를 사용합니다.

  • 삽입된 로우의 모든 컬럼 값을 기록
  • 삭제된 로우를 고유하게 식별하는 정보 기록
  • 수정된 로우를 식별하는 정보와 새로운 컬럼 값 기록

장점

  • 저장소 엔진 내부와 독립적이어서 버전 호환성 문제가 적음
  • 외부 애플리케이션이 로그를 파싱하기 쉬움 (데이터 웨어하우스 등)

4. 트리거 기반 복제(Trigger-Based Replication)

애플리케이션 레벨에서 복제를 처리하는 방식입니다.

  • 데이터베이스의 트리거(Trigger)나 스토어드 프로시저(Stored Procedure)를 사용
  • 데이터 변경이 발생하면 트리거가 실행되어 변경 사항을 별도의 테이블에 기록
  • 외부 프로세스가 이 테이블을 읽어 다른 시스템에 복제

특징

  • 더 유연하지만 오버헤드가 크고 버그 발생 가능성이 높음
  • 특정 데이터만 선택적으로 복제하거나 복잡한 충돌 해결이 필요한 경우에 유용

복제 지연 문제

비동기식 복제를 사용하면 복제 지연(replication lag)이 발생할 수 있으며, 이로 인해 일관성 문제가 생깁니다.

1. 쓰기 후 읽기 일관성(Read-After-Write Consistency)

문제 상황

  • 사용자가 쓰기를 수행한 직후, 복제가 완료되지 않은 팔로워에서 데이터를 읽으면 방금 쓴 내용이 보이지 않음

해결 방법

  • 사용자가 수정한 내용을 읽을 때는 리더에서 읽기
  • 마지막 쓰기 후 일정 시간 동안은 리더에서 읽기
  • 타임스탬프 기반으로 복제 서버 선택
    • 클라이언트가 가장 최근 쓰기의 타임스탬프를 기억
    • 해당 타임스탬프까지 업데이트가 적용된 복제 서버에서만 읽기

2. 단조 읽기(Monotonic Reads)

문제 상황

  • 시간이 거꾸로 흐르는 현상 발생
  • 사용자가 먼저 최신 데이터를 가진 복제 서버에서 읽고, 그 다음 복제 지연이 있는 다른 복제 서버에서 읽으면 이전에 봤던 데이터가 사라진 것처럼 보임

해결 방법

  • 각 사용자의 읽기가 항상 동일한 복제 서버에서 수행되도록 보장
  • 예: 사용자 ID의 해시를 기반으로 복제 서버를 선택하여 동일 사용자는 항상 같은 서버에 연결

3. 일관된 순서로 읽기(Consistent Prefix Reads)

문제 상황

  • 여러 파티션에 분산된 데이터를 읽을 때, 인과관계가 있는 쓰기들이 순서가 뒤바뀌어 보일 수 있음
  • 예: 질문과 답변이 역순으로 표시되는 경우

해결 방법

  • 인과관계가 있는 쓰기는 동일한 파티션에 기록
  • 복제 지연을 추적하여 인과적으로 관련된 쓰기가 모두 적용된 후에 읽기

리더 없는 복제(Leaderless Replication)

리더가 쓰기를 담당하는 것이 아닌, 모든 복제 서버가 클라이언트로부터 쓰기를 직접 받을 수 있게 허용하는 방식입니다. Dynamo, Riak, Cassandra 등에서 사용됩니다.

읽기 복구(Read Repair)

클라이언트가 여러 노드에서 병렬로 읽기를 수행할 때:

  • 오래된 값을 감지하면 새로운 값을 해당 복제 서버에 다시 쓰는 방식
  • 자주 읽히는 데이터에 효과적

안티 엔트로피(Anti-Entropy)

백그라운드 프로세스가 복제 서버 간의 데이터 차이를 지속적으로 찾아서 복사하는 방식:

  • 읽기 요청이 없어도 데이터 일관성 유지
  • 복제에 상당한 지연이 있을 수 있음

읽기와 쓰기를 위한 정족수(Quorum)

n개의 복제 서버가 있을 때:

  • 쓰기: w개의 노드에서 쓰기가 성공해야 확정
  • 읽기: r개의 노드에서 읽기를 수행
  • 정족수 조건: w + r > n이면 최신 값을 읽을 수 있음을 보장

일반적인 설정

  • n = 3, w = 2, r = 2
  • 한 개의 노드 장애를 견딜 수 있으면서도 최신 데이터 읽기 보장

특징

  • w, r 값을 조정하여 읽기/쓰기 성능과 내구성의 균형을 맞출 수 있음
  • w = n, r = 1: 읽기에 최적화 (모든 노드에 쓰기 완료 필요)
  • w = 1, r = n: 쓰기에 최적화 (한 노드에만 쓰기, 모든 노드에서 읽기)
profile
아직 배고프다

0개의 댓글