가상 면접 사례로 배우는 대규모 시스템 설계 기초 서적의 5, 6장과 개인적으로 공부했던 내용을 정리했습니다.
key-value 저장소는 Non Sql DB로 저장되는 모든 값은 고유 식별자를 키로 가지고 있습니다.
널리 알려진 것으로 Redis, 아마존 다이나모 등이 있습니다.
key-value 저장소를 설계시 기대하는 요구사항은 다음과 같습니다.
이러한 요구사항들을 만족시키기 위해 여러 기법과 기술들이 존재합니다.
가장 쉬운 방법은 키-값 쌍 전부를 메모리에 해시테이블로 저장하는 것입니다.
메모리에서 관리하기에 작업을 빠르게 처리할 수 있습니다.
하지만 용량 상 모든 데이터를 메모리에 넣는 것이 불가능할 수 있습니다.
서비스의 규모가 크다면 단일 서버만으로 관리하기 어렵고, SPOF문제가 발생할 수 있습니다.
따라서 분산된 키-값 저장소를 사용할 수 있습니다.
Consistency, Availability, Partition tolerance를 동시에 만족하는 분산 시스템은 불가능하다
분산 시스템은 네트워크를 이용해 분산 서버간 통신을 합니다.
이때 네트워크 통신 장애는 피할 수 없기때문에 모든 분산 시스템은 파티션 감내를 만족해야합니다.
파티션 문제가 발생하면 시스템은 일관성, 가용성 중 하나를 선택해야 합니다.
다음으로 키-값 저장소 구현의 핵심 컴포넌트와 기술들을 살펴보겠습니다.
데이터를 작은 파티션으로 분할한 다음 여러 대의 서버에 저장합니다.
파티션을 나눌 때는 다음 문제들을 고려해야 합니다.
이러한 문제들을 고려했을때 안정 해시가 적합합니다.

기존 해시 함수를 사용해 키를 균등하게 서버에 보관할 시,
서버가 추가, 삭제될때마다 대부분의 키가 모듈러 연산에 의해 재분배되어 대규모의 캐시 미스 장애가 발생할 수 있습니다.
따라서 안정 해시는 해시 순환 링에 서버와 키 값을 배치합니다.
특정 키 값에서 가장 가까운 서버에서 값을 조회하고,
서버를 추가, 제거 시에도 해시 링에서 가까운 거리의 키-값 쌍들만 재배치합니다.
다시 돌아와서 높은 가용성, 안정성을 확보하기 위해서는 데이터를 N개의 여러 서버에 비동기적으로 다중화해야 합니다.
이는 안정 해시의 해시 링으로 구현할 수 있습니다.
이때 N개의 노드 갯수가 실제 물리 서버 갯수보다 커서 물리 서버를 중복 선택하지 않도록 해야합니다.
앞서 보았듯이 여러 노드에 다중화된 데이터는 적절히 동기화를 해주어 데이터 일관성을 유지해야할 필요가 있습니다.
이때 정족수 합의 프로토콜을 사용하면 읽기/쓰기에 모두 일관성을 유지할 수 있습니다.
N = 사본 갯수, W = 쓰기 연산 갯수, R = 읽기 연산 정족수
W, R이 커지면 일관성 수준이 향상되나 응답 속도가 느려집니다.
데이터의 다중화는 가용성을 높이지만 사본 간 일관성이 깨질 가능성이 높아집니다.
따라서 이를 해소하기 위한 기법들이 존재합니다.
데이터를 변경할 때마다 해당 데이터의 새로운 버전 생성하고, 기존 버전은 무시합니다.
(서버, 버전)의 순서쌍을 데이터에 매달아 저장합니다.
(Si, vi)의 형태 - 이미 있으면 vi를 증가시킨다, 없으면 새 항목 (Si, 1)을 만든다
D3({Sx, 2}, {Sy, 1}), D4({Sx, 2},{Sz, 1}) 같은 버전 데이터 충돌 시
해당 데이터 읽은 클라이언트가 해소 후 서버에 기록 D5({Sx,3},{Sy,1},{Sz,1})
장애는 분산 서버에서 아주 흔하게 발생합니다. 따라서 장애 감지 기법, 장애 해소 전략이 필요합니다.
두 대 이상의 서버가 장애를 보고해야 실제 장애가 발생했다고 간주합니다.
모든 노드를 그물망처럼 연결하는 멀티 캐스팅 채널을 구축하는 방법이 쉬우나, 서버가 많으면 비효율적입니다.
서버가 많을때는 가십 프로토콜같은 분산형 장애 감지 솔루션을 채택하는 편이 효율적입니다.
장애 상태인 서버로 가는 요청은 다른 서버가 잠시 맡아 처리합니다.
-> 해당 서버가 복구되었을때 일괄 반영하여 데이터 일관성 보존
=> 이를 위해서 임시로 쓰기 연산을 처리한 서버에 단서(hint)를 남겨둔다
-> 단서 후 임시 위탁 기법
영구적인 장애를 처리할때는 사본들을 비교하여 최신 버전으로 갱신하여 동기화해주어야 합니다.
이때 머클트리를 사용하면 보안 상 안전하고 효과적으로 사본을 검증할 수 있습니다.

즉 머클 트리를 사용하면 모든 데이터를 동기화할 필요 없이 차이가 존재하는 버킷만 동기화할 수 있습니다.
정전, 네트워크 장애, 자연 재해 등으로 인해 데이터 센터도 장애가 발생할 수 있기 때문에
데이터를 여러 데이터 센터에 다중화해야합니다.
카카오 데이터센터 화재 사례
데이터가 메모리에 있다면 반환
데이터가 메모리에 없다면 디스크에서 가져와야함 -> Bloom filter 사용
1. 데이터가 메모리(Memtable)에 있는지 검사
2. 블룸 필터 검사
3. 블룸 필터로 어떤 SSTable에 키가 보관되어 있는지 찾는다
4. 해당 SSTable에서 데이터를 가져온다
5. 해당 데이터를 클라이언트에 반환
이 때 Memtable로 LSM Tree 구조를 많이 사용합니다.
메모리의 특성상 장애 휘발될 수 있으므로 데이터 손실을 방지하고자 memtable 데이터는 디스크에 log file로 따로 저장합니다.