6. Key-Value System Design
키-값 저장소 설계
요약
대규모 데이터 저장: 안정 해시를 사용해 서버들에 부하 분산
읽기 연산에 대한 높은 가용성 보장: 데이터를 여러 데이터센터에 다중화
쓰기 연산에 대한 높은 가용성 보장: 버저닝 및 벡터 시계를 사용한 충돌 해소
데이터 파티션: 안정 해시
점진적 규모 확장성: 안정 해시
다양성(Hetrogeneity): 안정 해시
조절 가능한 데이터 일관성: 정족수 합의
일시적 장애처리: 느슨한 정족수 프로토콜과 단서 후 임시 위탁
영구적 장애 처리: 머클 트리
데이터 센터 장애 대응: 여러 데이터 센터에 걸친 데이터 다중화
1. 문제 이해 및 설계 범위 확정
키-값 저장소(Key-Value Store)는 대규모 분산 시스템에서 자주 사용되는 데이터 저장 방식 중 하나로, 빠르고 유연한 데이터 접근이 요구되는 환경에서 활용된다. 이 저장소는 하나의 키에 대응하는 하나의 값을 저장하는 단순한 구조로, 대용량 데이터를 효율적으로 관리하고 빠르게 조회할 수 있는 기능을 제공한다.
설계 범위 확정은 이 시스템이 단일 서버에서 작동하는 간단한 구조인지, 아니면 여러 서버에 걸쳐 데이터를 분산 저장하고 관리하는 복잡한 분산 시스템인지에 따라 달라진다. 이 글에서는 단일 서버 키-값 저장소의 설계부터 시작해, 분산 환경에서의 키-값 저장소 설계까지를 단계적으로 설명한다.
2. 단일 서버 키-값 저장소
단일 서버에서의 키-값 저장소는 비교적 단순한 구조를 가지며, 기본적으로 해시 테이블(Hash Table)과 유사한 동작을 한다. 클라이언트는 특정 키에 대해 값을 저장하거나, 해당 키에 대한 값을 조회하는 작업을 수행한다. 이러한 키-값 쌍은 메모리 내에 저장되거나 파일 시스템에 저장될 수 있다.
기본 기능:
저장(Put/Set): 특정 키에 값을 저장하는 연산.
조회(Get): 특정 키에 해당하는 값을 조회하는 연산.
삭제(Delete): 특정 키에 해당하는 데이터를 삭제하는 연산.
단일 서버 키-값 저장소의 가장 큰 장점은 구현이 간단하며, 읽기/쓰기 연산이 매우 빠르다는 점이다. 그러나 단일 서버에 모든 데이터가 저장되므로 서버가 고장 나거나 성능에 병목이 생기면 시스템 전체가 영향을 받게 된다.
3. 분산 키-값 저장소
단일 서버의 한계를 극복하기 위해, 키-값 저장소는 여러 대의 서버에 데이터를 분산하여 저장하는 분산 시스템으로 확장될 수 있다. 이 과정에서 다양한 설계 요소가 추가되며, 데이터의 일관성, 가용성, 파티셔닝 등의 문제가 중요하게 다뤄진다.
3.1 CAP 정리 (CAP Theorem)
CAP 정리는 분산 시스템에서 일관성(Consistency), 가용성(Availability), 그리고 네트워크 분할 허용성(Partition Tolerance) 중 두 가지 특성만을 동시에 만족시킬 수 있다는 이론이다. 이는 분산 키-값 저장소 설계 시 중요한 고려 사항이다.
데이터 일관성: 항상 같은 데이터를 보게 되어야한다. 분산 시스템에 접속하는 모든 클라이언트는 어떤 노드에 접속했는냐에 관계없이 언제나 같은 데이터를 보게 되어야 한다.
가용성: 항상 응답을 받아야한다. 분산 시스템에 접속하는 클라이언트는 일부 노드에 장애가 발생하더라도 항상 응답을 받을 수 있어야한다.
파티션 감내: 네트워크에 통신 장애가 발생해도 시스템은 동작해야한다.
CP 시스템: 가용성을 희생하여 일관성과 파티션 감내
AP 시스템: 일관성을 희생하여 가용성과 파티션을 감내
CA 시스템: 파티션 감내를 희생하여 일관성과 가용성 (실세계에 존재하지 않음)
이상적 상태: 이론적으로, 분산 시스템은 일관성과 가용성을 모두 제공하는 것이 이상적이다. 즉, 모든 노드가 항상 동일한 데이터를 제공하고, 언제든지 데이터를 읽고 쓸 수 있어야 한다.
실세계의 분산 시스템: 그러나 현실에서는 네트워크 지연이나 장애로 인해 일관성과 가용성 간의 균형을 맞춰야 한다. 예를 들어, 네트워크 분할이 발생하면 시스템은 일관성을 유지할 것인지, 가용성을 유지할 것인지 선택해야 한다. 대부분의 분산 시스템은 네트워크 분할을 허용하면서도 가능한 높은 일관성과 가용성을 유지하려는 전략을 채택한다.
4. 시스템 컴포넌트
분산 키-값 저장소를 설계할 때 고려해야 할 주요 시스템 컴포넌트:
4.1 데이터 파티션 (Data Partition)
데이터 파티션은 대규모 시스템에서 데이터를 효율적으로 분산하여 저장하는 핵심 기법이다. 분산 시스템에서는 전체 데이터를 하나의 서버에 저장하는 것이 비효율적이기 때문에, 여러 서버에 데이터를 나눠서 저장하는 방식이 필요하다. 이를 파티셔닝이라 하며, 다음과 같은 방법들이 있다.
범위 기반 파티셔닝(Range-Based Partitioning): 키의 범위에 따라 데이터를 나누는 방식이다. 예를 들어, 키가 'A'부터 'M'까지인 데이터를 한 파티션에, 'N'부터 'Z'까지인 데이터를 다른 파티션에 저장한다. 이 방식은 특정 범위의 데이터 접근이 자주 발생할 때 효율적이나, 특정 파티션에 데이터가 몰릴 가능성이 있다.
해시 기반 파티셔닝(Hash-Based Partitioning): 키의 해시 값을 계산하여 파티션을 정하는 방식이다. 해시 함수의 결과에 따라 데이터가 균등하게 분산되므로, 범위 기반 파티셔닝의 단점을 보완할 수 있다.
일관된 해싱(Consistent Hashing): 시스템의 규모 확장성을 고려한 해시 기반 파티셔닝 기법으로, 서버가 추가되거나 제거될 때 데이터의 이동을 최소화할 수 있다. 이 기법은 대규모 분산 시스템에서 널리 사용된다. (5장 안정 해시)
4.2 데이터 다중화 (Data Replication)
데이터 다중화는 하나의 데이터를 여러 서버에 복제하여 저장하는 방식으로, 장애 발생 시에도 데이터 접근성을 보장하기 위해 사용된다. 데이터 다중화는 데이터의 가용성과 신뢰성을 높이는 중요한 요소로 작용한다. 데이터 다중화에는 두 가지 주요 방식이 있다.
동기 다중화(Synchronous Replication): 모든 복제본에 데이터가 동기화된 상태로 저장되는 방식이다. 이는 데이터의 일관성을 보장하지만, 쓰기 지연(latency)이 증가할 수 있다. 예를 들어, 데이터가 모든 복제본에 쓰여질 때까지 클라이언트는 응답을 받지 못한다.
비동기 다중화(Asynchronous Replication): 데이터를 하나의 서버에 먼저 저장하고, 이후 다른 서버에 비동기적으로 복제하는 방식이다. 이는 쓰기 성능을 높이는 데 유리하지만, 일시적인 일관성 문제(inconsistency)가 발생할 수 있다.
4.3 데이터 일관성 (Data Consistency)
데이터 일관성은 분산 시스템에서 동일한 데이터에 대한 여러 복제본 간의 일관성을 유지하는 것을 의미한다. 데이터 일관성을 유지하기 위한 여러 일관성 모델이 존재하며, 시스템의 요구 사항에 따라 적절한 모델을 선택해야 한다.
강한 일관성(Strong Consistency): 모든 데이터 복제본이 항상 동일한 값을 갖도록 보장하는 모델이다. 클라이언트는 항상 최신 데이터를 읽을 수 있지만, 이로 인해 쓰기 성능이 저하될 수 있다.
최종 일관성(Eventual Consistency): 일시적으로 복제본 간의 데이터가 불일치할 수 있지만, 시간이 지나면서 결국 모든 복제본이 일관된 상태에 도달하는 모델이다. 이는 빠른 쓰기 성능을 제공하면서도 데이터 일관성을 어느 정도 유지할 수 있는 타협점이다.
약한 일관성(Weak Consistency): 특정 시점에 데이터가 일관성을 보장하지 않을 수 있는 모델이다. 이는 주로 빠른 쓰기 성능이 요구되는 시스템에서 사용된다.
비 일관성 해소 기법: 데이터 버저닝 (Data Versioning)
데이터 버저닝은 동일한 데이터에 대한 여러 버전을 관리하는 기법으로, 충돌 해결에 사용된다. 이는 주로 최종 일관성 모델에서 데이터 불일치를 해결하는 데 중요한 역할을 한다.
벡터 시계(Vector Clock): 각 서버가 데이터 버전을 기록하여, 충돌 발생 시 어떤 데이터가 최신인지를 결정하는 데 사용된다. 벡터 시계는 서버 간에 데이터의 인과 관계를 추적할 수 있도록 한다. 충돌이 발생했을시 인과 관계를 따져서 수동 또는 추가적 타임스탬프를 유지하여 자동으로 해결.
람포트 타임스탬프(Lamport Timestamp): 각 이벤트에 대해 단일 시간 값을 기록하여, 어떤 데이터가 최신인지를 결정하는 데 사용된다. 벡터 시계에 비해 간단하지만, 여러 서버 간의 복잡한 충돌을 해결하는 데는 부족할 수 있다. (상대적 시간일뿐, 물리적 시간과는 무관)
장애 처리 (Fault Tolerance)
장애 처리는 시스템의 신뢰성을 보장하기 위해 다양한 장애 상황에 대응하는 방법을 포함한다. 장애 처리는 장애의 유형에 따라 다양한 대응 전략이 필요하다.
장애 감지(Fault Detection): 장애를 신속히 감지하기 위한 메커니즘으로, 하트비트(Heartbeat) 방식이 주로 사용된다. 각 서버는 주기적으로 다른 서버에 신호를 보내고, 이 신호가 중단되면 해당 서버에 장애가 발생했음을 감지한다.
일시적 장애 처리(Transient Fault Handling):
강한 정족수 프로토콜: 읽기, 쓰기 금지
느슨한 정족수 프로토콜: 장애 서버를 제외한 W, R 목록 선정
영구적 장애 처리(Permanent Fault Handling): 반 엔트로피 프로토콜과 머클 트리를 사용하여 사본들을 동기화
데이터 센터 장애 처리(Data Center Fault Handling): 데이터 센터 전체가 장애를 일으켰을 때에도 서비스의 지속성을 보장하기 위해, 여러 데이터 센터에 데이터를 다중화하는 방법이다. 이 방법은 시스템의 가용성과 신뢰성을 극대화하는 데 중요한 역할을 한다.
5. 시스템 아키텍처 다이어그램
분산 키-값 저장소의 설계를 이해하기 위해서는 시스템 아키텍처 다이어그램이 필요하다. 이 다이어그램은 각 컴포넌트가 어떻게 상호작용하는지를 시각적으로 표현하며, 전체 시스템의 구조를 명확하게 보여준다.
기본 아키텍처 구성 요소:
클라이언트(Client): 데이터에 접근하려는 사용자나 애플리케이션을 의미하며, 키-값 저장소에 데이터를 읽거나 쓰기 위해 요청을 보낸다.
중재자 (Arbiter): 중재자는 클라이언트 요청을 처리하고, 이를 적절한 노드로 라우팅하거나 데이터 일관성을 관리하는 역할을 합니다. 중재자는 로드 밸런싱, 장애 감지, 데이터 일관성 유지 등의 기능을 수행할 수 있습니다.
키-값 서버(Key-Value Server): 실제로 데이터를 저장하고 관리하는 서버들로, 여러 대의 서버가 협력하여 전체 데이터를 관리한다.
메타데이터 서버(Metadata Server): 데이터 파티션, 복제, 일관성 관리 등 시스템의 메타데이터를 관리하는 서버로, 시스템의 상태를 추적하고 조정한다.
이러한 구성 요소들이 상호작용하여 데이터의 읽기 및 쓰기 요청을 처리한다. 아키텍처 다이어그램은 시스템의 각 요소가 어떤 역할을 하는지, 그리고 전체적으로 어떻게 동작하는지를 이해하는 데 필수적이다.
6. 쓰기 경로 (Write Path)
쓰기 경로는 클라이언트가 키-값 저장소에 데이터를 쓰는 과정이다. 분산 시스템에서의 쓰기 연산은 여러 서버에 걸쳐 일어나므로, 일관성 및 가용성을 보장하기 위한 다양한 기법이 적용된다.
클라이언트 요청: 클라이언트는 로드 밸런서를 통해 쓰기 요청을 보낸다. 이 요청은 데이터의 키와 값을 포함하며, 어떤 데이터가 저장될지를 결정한다.
파티셔닝 결정: 로드 밸런서는 메타데이터 서버와 협력하여, 요청된 데이터가 어떤 서버에 저장될지를 결정한다. 이 과정에서 일관된 해싱 기법이 사용될 수 있다.
데이터 다중화: 요청된 데이터는 여러 서버에 복제되며, 동기 또는 비동기 방식으로 다중화된다. 동기 방식에서는 모든 복제본에 데이터가 쓰여질 때까지 클라이언트는 응답을 기다려야 한다.
쓰기 확인: 데이터가 성공적으로 저장되면, 각 서버는 쓰기 작업이 완료되었음을 로드 밸런서에 알리고, 로드 밸런서는 이를 클라이언트에 전달한다.
이 과정에서 장애가 발생할 경우, 비동기 다중화 또는 쓰기 지연을 감수하여 시스템이 계속 작동하도록 조정할 수 있다.
7. 읽기 경로 (Read Path)
읽기 경로는 클라이언트가 키-값 저장소에서 데이터를 읽는 과정이다. 읽기 연산 역시 여러 서버에 걸쳐 일어나며, 일관성을 보장하기 위해 다양한 접근 방법이 적용된다.
클라이언트 요청: 클라이언트는 읽기 요청을 로드 밸런서를 통해 보낸다. 이 요청은 특정 키에 해당하는 값을 조회하기 위한 것이다.
데이터 위치 확인: 로드 밸런서는 메타데이터 서버를 통해, 요청된 데이터가 저장된 서버를 확인한다. 이 과정에서 파티셔닝 정보와 복제본의 상태를 고려한다.
데이터 조회: 로드 밸런서는 여러 서버에 데이터를 요청하며, 일반적으로 가장 빠르게 응답한 서버로부터 데이터를 가져온다. 이 경우, 최종 일관성 모델이 적용되어 데이터가 일시적으로 일관되지 않을 수 있다.
데이터 반환: 로드 밸런서는 클라이언트에게 데이터를 반환하며, 일관성 모델에 따라 복제본 간의 데이터 동기화를 시도할 수 있다.
읽기 경로에서의 주요 고려 사항은 데이터의 일관성과 응답 시간이다. 일관성을 우선할지, 성능을 우선할지에 따라 최적의 방법을 선택해야 한다.
Last updated