키-값 저장소의 대표적인 비관계형DB는 아래 3가지가 있다.
put(key, value) : 키-값 쌍을 저장소에 저장한다.
get(key) : 인자로 주어진 키에 매달린 값을 꺼낸다.
한 대 서버만 사용하는 키-값 저장소를 설계할 경우에는 해시 테이블로 저장하는 것이 가장 바람직하다. 장점으로는 속도를 보장하지만 단점으로는 모든 데이터를 메모리 안에 두는 것이 불가능할 수도 있다는 약점을 갖고 있다.
이 문제를 해결하기 위해서는 데이터 압축, 자주 사용하는 데이터만 메모리에 두고 나머지는 디스크에 저장 하지만 한 대 서버로 부족할 경우가 오게 된다. 많은 데이터를 저장하기 위해서는 분산 키-값 저장소를 만들 필요가 있다.
분산 키-값 저장소는 분산 해시 테이블이라고도 불린다. 분산 시스템을 설계할 때는 cap 정리를 이해하고 있어야 한다.
C: consistency (일관성)
A: availability (가용성)
P: partition tolerance(파티션 감내)
세 가지 요구사항을 동시에 만족하는 분산 시스템을 설계하는 것은 불가능하다는 정리다.
데이터 일관성: 시스템에 접속하는 모든 클라이언트는 어떤 노드에 접속했느냐에 관계없이 언제나 같은 데이터를 볼 수 있어야 한다.
가용성: 분산 시스템에 접속하는 클라이언트는 일부 노드에 장애가 발생하더라도 항상 응답을 받을 수 있어야 한다.
파티션 감내: 파티션은 두 노드 사이에 통신 장애가 발생하였음을 의미한다. 네트워크에 파티션이 생기더라도 시스템은 계속 동작하여야 한다는 것을 뜻한다.
cap이론은 이들 가운데 어떤 두 가지를 충족하려면 나머지 하나는 반드시 희생되어야 한다는 것을 의미한다.
CP 시스템: 일관성과 파티션 감내를 지원하는 키-값 저장소, 가용성을 희생
AP 시스템: 가용성과 파티션 감내를 지원하는 키-값 저장소, 데이터 일관성 희생
CA 시스템: 일관성과 가용성을 지원하는 키-값 저장소, 파티션 감내는 지원하지 않는다. 하지만 분산 시스템은 반드시 파티션 문제를 감내할 수 있도록 설계되어야 한다. 그러므로 실세계에 CA 시스템은 존재하지 않는다.
이상적인 환경에서는 네트워크가 파티션되는 상황은 절대로 일어나지 않는다. n1에 기록된 데이터는 자동적으로 n2와 n3에 복제되며, 데이터의 일관성과 가용성도 만족한다.

분산 시스템은 파티션 문제를 피할 수 없다. 또한 파티션 문제가 발생하면 일관성과 가용성 사이에서 하나만 선택해야 한다. n3에 장애가 발생하면 n1 및 n2와 통신할 수 없는 상황이 생기고, 데이터가 n3에 기록되었으나 n1 및 n2로 전달되지 않은 데이터가 있다면 오래된 사본을 갖고 있을 것이다.
가용성 대신 일관성을 선택한다면 3개의 서버 사엥 생길 수 있는 데이터 불일치 문제를 피하기 위해 n1과 n2에 대해 쓰기 연산을 중단시켜야 하는데 그렇게하면 가용성이 깨지게 된다.
키-값 저장소 구현에 사용될 핵심 컴포넌터들 및 기술들을 살펴보자
대규모 애플리케이션의 경우 전체 데이터를 한 대 서버에 넣는 것은 불가능하다.
가장 단순한 방법은 데이터를 작은 파티션으로 분할한 다음 여러 대 서버에 저장하는 것이다.
고려해야 할 사항

안정 해시를 사용하여 데이터를 파티션하면 좋다.
규모 확장 자동화: 시스템 부하에 따라 서버가 자동으로 추가되거나 삭제됨
다양성: 각 서버의 용량에 맞게 가상 노드의 수를 조정할 수 있음
높은 가용성과 안전성을 확보하기 위해 데이터를 N개 서버에 비동기적으로 다중화할 필요가 있다. 어떤 키를 해시 링 위에 배치한 후, 그 지점으로부터 시계 방향으로 링을 순회하면서 만나는 첫 N개 서버에 데이터 사본을 보관하는 것이다.

노드를 선택할 때 같은 물리 서버를 중복으로 선택하지 않도록 해야한다. 안전성을 담보하기 위해 데이터의 사본은 다른 센터의 서버에 보관하고, 센터들은 고속 네트워크로 연결한다.
여러 노드에 다중화된 데이터는 적절히 동기화가 되어야 한다. 정족수 합의 프로토콜을 사용하면 읽기/쓰기 연산 모두에 일관성을 보장할 수 있어야 한다.
N = 사본 개수
W = 쓰기 연산에 대한 정족수
N = 읽기 연산에 대한 정족수

W + R > N 경우에는 강한 일관성이 보장되며, 일관성을 보증할 최신 데이터를 가진 노드가 최소 하나는 겹칠 것이다.
R = 1, W = N: 빠른 읽기 연산에 최적화된 시스템
W = 1, R = N: 빠른 쓰기 연산에 최적화된 시스템
일관성 모델은 키-값 저장소를 설계할 때 고려해야 할 또 하나의 중요한 요소이다.
강한 일관성: 모든 읽기 연산은 가장 최근에 갱신된 결과를 반환한다.
약한 일관성: 읽기 연산은 가장 최근에 갱신된 결과를 반환하지 못할 수 있다.
최종 일관성: 약한 일관성의 한 형태로, 갱신 결과가 결국에는 모든 사본에 반영되는 모델
강한 일관성은 쓰기 연산의 결과가 반영될 때까지 해당 데이터에 대한 읽기/쓰기를 금지하는 것이다. 이 방법은 고가용성 시스템에는 적합하지 않다. 최종 일관성 모델을 따를 경우 쓰기 연산이 병렬적으로 발생하면 시스템에 저장된 값의 일관성이 깨질 수 있는데 이 경우 클라이언트가 해결해야 한다.
데이터를 다중화하면 가용성은 높아지지만 사본 간 일관성이 깨질 가능성은 높아진다. 버저닝과 벡터 시계는 그 문제를 해소하기 위해 등장한 기술이다.
버저닝은 데이터를 변경할 때마다 해당 데이터의 새로운 버전을 만드는 방법이다.
장애는 아주 흔하게 벌어지는 사건이다. 우선 장애 감지 기법들을 살펴보고 장애 해소 전략을 살펴보자
분산 시스템에서 장애처리를 할 경우는 두 대 이상의 서버가 똑같이 서버 A의 장애를 보고해야 해당 서버에 실제로 장애가 발생했다고 간주하게 된다. 모든 노드 사이에 멀티캐스팅 채널을 구축하는 것이 서버 장애를 감지하는 가장 손쉬운 방법이지만 서버가 많을 떄는 비효율적이다. 그래서 가십 프로토콜 같은 분산형 장애 감지 솔루션을 채택하는 편이 보다 효율적이다.
가십 프로토콜로 장애를 감지한 시스템은 가용성을 보장하기 위해 필요한 조치를 해야 한다. 엄격한 정족수 접근법을 쓴다면, 앞서 데이터 일관성 절에서 설명한 대로, 읽기와 쓰기 연산을 금지해야 할 것이다.
느슨한 정족수 접근법은 이 조건을 완화하여 가용성을 높인다. (W개의 건강한 서버와 R개의 건강한 서버를 해시 링에서 고른다. 이때 장애 서버는 무시) 네트워크나 서버 문제로 장애 상태인 서버로 가는 요청은 다른 서버가 잠시 맡아 처리한다. 그 동안의 변경 사항은 해당 서버가 복구되었을 떄 일괄 반영하여 데이터의 일관성을 반영한다.
단서 후 임시 위탁 기법은 일시적으로 장애를 처리하기 위한 것이다. 영구적인 노드의 장애 상태는 반-엔트로피 프로토콜을 구현하여 사본들을 동기화할 것이다. 반-엔트로피 프로토콜은 사본들을 비교하여 최신 버전으로 갱신하는 과정을 포함한다. 전송 데이터의 양을 줄이기 위해 머클 트리를 사용할 것이다.
트리 형식을 이용하여 아래쪽으로 탐색해 나가다 보면 다른 데이터를 갖는 버킷을 찾을 수 있고 그 버킷들만 동기화해주는 방식이다.
