데이터 중심 애플리케이션 설계05
복제
데이터 복제란?
데이터 복제는 네트워크로 연결된 여러 머신에 동일한 데이터의 복사본을 유지하는 것을 의미합니다.
복제의 목적
데이터 복제를 사용하는 주요 이유는 다음과 같습니다:
신뢰성 향상: 하드웨어 장애나 소프트웨어 오류로 인한 데이터 유실을 방지합니다. 여러 복제본을 유지함으로써 단일 장애점을 제거할 수 있습니다.
가용성 증대: 시스템의 일부가 실패하더라도 다른 복제본을 통해 서비스를 계속 제공할 수 있습니다. 이는 24/7 서비스를 운영하는 현대 애플리케이션에서 필수적입니다.
읽기 확장성: 읽기 요청을 여러 복제본에 분산하여 시스템의 읽기 처리량을 향상시킬 수 있습니다. 이는 읽기 중심의 워크로드에서 특히 유용합니다.
지연 시간 감소: 사용자와 지리적으로 가까운 복제본을 사용하여 네트워크 지연을 줄일 수 있습니다. 글로벌 서비스에서는 각 지역에 복제본을 배치하는 것이 일반적입니다.
리더-기반 복제(Leader-Based Replication)
가장 널리 사용되는 복제 방식으로, 마스터-슬레이브 복제 또는 액티브/패시브 복제라고도 불립니다.
작동 방식
리더-기반 복제에서는 모든 쓰기 요청이 리더(leader) 노드에서 처리됩니다. 리더는 변경 사항을 팔로워(follower) 노드들에게 복제하며, 클라이언트는 리더나 팔로워 모두에서 읽기를 수행할 수 있습니다.
이 방식의 장점은 구현이 상대적으로 간단하고, 쓰기 순서가 보장된다는 점입니다. PostgreSQL, MySQL, MongoDB 등 많은 데이터베이스가 이 방식을 사용합니다.
동기 vs 비동기 복제
동기 복제는 리더가 모든 팔로워의 확인을 받은 후에만 클라이언트에 성공을 보고합니다. 이는 강한 일관성을 보장하지만, 하나의 팔로워라도 응답하지 않으면 전체 시스템이 멈출 수 있습니다.
비동기 복제는 리더가 팔로워의 응답을 기다리지 않고 즉시 성공을 보고합니다. 이는 높은 성능과 가용성을 제공하지만, 리더가 실패하면 아직 복제되지 않은 데이터가 유실될 수 있습니다.
실제 시스템에서는 반동기(semi-synchronous) 방식을 사용하는 경우가 많습니다. 일부 팔로워는 동기적으로, 나머지는 비동기적으로 복제하여 성능과 안정성의 균형을 유지합니다.
노드 장애 처리
팔로워 장애는 상대적으로 간단합니다. 팔로워가 복구되면 리더로부터 누락된 변경 사항을 따라잡으면 됩니다.
리더 장애는 더 복잡한 페일오버(failover) 과정이 필요합니다:
- 리더가 실패했는지 판단 (일반적으로 타임아웃 기반)
- 새로운 리더 선출 (보통 가장 최신 데이터를 가진 팔로워)
- 클라이언트를 새 리더로 재구성
- 이전 리더가 복구되면 팔로워로 강등
이 과정에서 분리뇌(split-brain) 문제가 발생할 수 있습니다. 두 노드가 모두 자신이 리더라고 생각하면 데이터 일관성이 깨질 수 있습니다.
복제 지연 문제
비동기 복제에서는 복제 지연(replication lag)이 발생하며, 이는 실제 애플리케이션에서 다음과 같은 문제를 야기할 수 있습니다.
자신의 쓰기 읽기(Read-Your-Writes Consistency)
사용자가 데이터를 수정한 후 즉시 조회했는데 이전 값이 보이는 문제입니다. 예를 들어, 프로필을 업데이트한 후 새로고침했는데 이전 정보가 표시되는 경우입니다.
해결 방법:
- 사용자가 수정할 수 있는 데이터는 항상 리더에서 읽기
- 수정 후 일정 시간 동안은 리더에서 읽기
- 클라이언트가 마지막 업데이트 타임스탬프를 기억하고, 그보다 최신인 복제본에서만 읽기
단조 읽기(Monotonic Reads)
사용자가 여러 복제본에서 읽을 때 시간이 거꾸로 가는 것처럼 보이는 현상입니다. 첫 번째 읽기에서는 최신 데이터를, 두 번째 읽기에서는 더 오래된 데이터를 보는 경우입니다.
해결 방법:
- 각 사용자가 항상 동일한 복제본에서 읽도록 보장 (사용자 ID 해싱 등)
- 복제본의 타임스탬프를 추적하여 더 최신인 복제본에서만 읽기
일관된 접두사 읽기(Consistent Prefix Reads)
일련의 쓰기가 특정 순서로 발생했을 때, 읽기에서도 동일한 순서로 보이도록 하는 보장입니다. 인과관계가 있는 데이터에서 특히 중요합니다.
예를 들어, “질문”과 “답변”이 순서대로 작성되었는데, 다른 사용자가 “답변”만 먼저 보고 나중에 “질문”을 보는 경우가 발생할 수 있습니다.
다중-리더 복제(Multi-Leader Replication)
여러 데이터센터에 걸쳐 시스템을 운영할 때 유용한 방식입니다. 각 데이터센터에 리더를 두어 쓰기 성능을 향상시키고 네트워크 분할에 대한 내성을 높일 수 있습니다.
장점
- 성능 향상: 각 데이터센터에서 로컬 쓰기 처리
- 내결함성: 데이터센터 간 네트워크 문제에 강함
- 지역성: 사용자와 가까운 데이터센터에서 처리
쓰기 충돌 문제
다중-리더 시스템의 가장 큰 도전은 쓰기 충돌(write conflicts)입니다. 두 데이터센터에서 동시에 같은 레코드를 수정하면 충돌이 발생합니다.
충돌 해결 전략:
- 충돌 회피: 특정 레코드의 쓰기를 항상 같은 리더로 라우팅
- 최종 쓰기 승리(LWW): 타임스탬프 기반으로 최신 쓰기 선택
- 사용자 정의 로직: 애플리케이션에서 충돌 해결 로직 구현
- 충돌 보존: 충돌하는 모든 버전을 저장하고 나중에 해결
복제 토폴로지
- 모든-대-모든(All-to-All): 모든 리더가 서로 직접 복제
- 원형(Circular): 리더들이 원형으로 연결되어 복제
- 스타(Star): 중앙의 하나의 리더가 다른 모든 리더와 복제
각 토폴로지는 고유한 장단점과 복잡성을 가지며, 메시지 순서 문제와 단일 장애점 등을 고려해야 합니다.
리더리스 복제(Leaderless Replication)
Amazon DynamoDB, Cassandra, Riak 등에서 사용하는 방식으로, 지정된 리더 없이 모든 복제본이 쓰기를 직접 받을 수 있습니다.
작동 방식
클라이언트는 쓰기 요청을 여러 복제본에 병렬로 전송하고, 일정 수 이상의 복제본이 성공하면 쓰기가 성공한 것으로 간주합니다. 읽기 시에도 여러 복제본에서 병렬로 읽어 최신 값을 결정합니다.
노드 장애 처리
읽기 복구(Read Repair): 읽기 시 오래된 값을 감지하면 클라이언트가 최신 값을 다시 작성합니다.
안티-엔트로피(Anti-Entropy): 백그라운드 프로세스가 복제본 간의 차이를 지속적으로 찾아서 동기화합니다.
정족수(Quorums)
n
개의 복제본 중 w
개에서 쓰기 성공, r
개에서 읽기를 수행할 때, w + r > n
조건을 만족하면 최신 값을 읽을 수 있습니다.
예를 들어, n=3, w=2, r=2
인 경우, 읽기와 쓰기가 최소 하나의 노드에서 겹치므로 최신 값을 보장할 수 있습니다.
느슨한 정족수(Sloppy Quorums)은 네트워크 분할 시에도 가용성을 유지하기 위해 지정된 복제본 외의 노드에서도 일시적으로 쓰기를 수락하는 방식입니다.
동시 쓰기 감지
다중-리더나 리더리스 시스템에서는 동시 쓰기가 자연스럽게 발생하며, 이를 감지하고 해결하는 것이 중요합니다.
최종 쓰기 승리(Last Write Wins)
각 쓰기에 타임스탬프를 부여하고 가장 최신 타임스탬프를 가진 쓰기를 선택하는 방식입니다.
동시성과 인과관계
두 작업이 서로에게 인과적으로 의존하지 않을 때 동시적(concurrent)이라고 합니다. 물리적 시간과는 관계없이 논리적 의존성에 기반합니다.
버전 벡터(Version Vectors)
각 복제본의 버전 번호 컬렉션을 사용하여 인과적 의존성을 추적하는 방법입니다. 동시적으로 작성된 값들(siblings)을 구분할 수 있으며, 클라이언트가 이러한 충돌을 병합해야 할 수도 있습니다.
실무에서의 고려사항
복제를 설계할 때 다음 요소들을 고려해야 합니다:
일관성 vs 성능: 강한 일관성은 성능을 희생하고, 높은 성능은 일관성을 완화해야 합니다.
가용성 vs 일관성: CAP 정리에 따라 네트워크 분할 시 둘 중 하나를 선택해야 합니다.
운영 복잡성: 복제 방식이 복잡할수록 운영과 디버깅이 어려워집니다.
애플리케이션 요구사항: 실시간성이 중요한지, 데이터 유실을 절대 허용하지 않는지 등을 고려해야 합니다.
결론
데이터 복제는 분산 시스템의 핵심이지만, 많은 트레이드오프를 수반합니다. 각 복제 방식은 고유한 장단점을 가지며, 시스템의 요구사항에 따라 적절한 방식을 선택하는 것이 중요합니다.
완벽한 복제 솔루션은 존재하지 않으며, 일관성, 가용성, 성능, 운영 복잡성 사이의 균형을 찾아야 합니다. 무엇보다 복제로 인해 발생할 수 있는 문제들을 미리 이해하고 대비하는 것이 안정적인 분산 시스템을 구축하는 핵심입니다.