가상 면접 사례로 배우는 대규모 시스템 설계 기초 Study [6장] 키-값 저장소 설계
Contents
Note
팀 내에서 진행하는 Study 정리 입니다.
함께 논의하고 싶은 주제
- 분산 시스템에서 어떤 노드가 최신의 데이터를 갖고 있는지 어떻게 판단할지
키 값 저장소
- 키-값 데이터베이스라고도 하며 비 관계형 데이터베이스이다.
- 고유 식별자
identifier
를 키로 설정하며 키는 유일해야하고 키에 매달린 값은 키를 통해서만 접근 가능하다. - 키는 짧을 수록 좋다.
- 값은 문자열, 리스트, 객체 등 어떤 값이 오든 상관없다.
- 아마존 다이나모, memcached, 레디스 등
1. 문제 이해 및 설계 범위 확정
읽기, 쓰기 그리고 메모리 사용량 사이 균형을 찾고 데이터 일관성과 가용성 사이에 타협점을 찾는 설계를 한다
- 키-값 쌍의 크기를 정한다.
- 큰 데이터를 저장할 수 있어야 한다.
- 높은 가용성 제공해야 한다.
- 높은 규모 확장성을 제공
- 데이터의 이로간성
- 응답 지연시간이 짧아야 한다.
2. 단일 서버 키-값 저장소
- 가장 직관적인 방법은 키-값 쌍 전부를 메모리 해시 테이블로 저장
- 빠른 속도를 보장하나 모든 데이터를 메모리에 두는 것은 불가능
- 해결 방안
- 데이터 압축
compression
- 자주 쓰는 데이터만 메모리에 두고 나머지는 디스크에 저장
- 데이터 압축
3. 분산 키-값 저장소
- 분산 해시 테이블
- 분산 시스템 설계시 CAP 정리
Consistency
,Availability
,Partition Tolerance theorem
를 이해해야 함
3.1 CAP 정리
아래의 세가지 요구사항을 동시에 만족하는 분산 시스템 설계는 불가능하다.
- 일관성
consistency
: 분산 시스템에 접속하는 모든 클라이언트는 언제가 같은 데이터를 보아야 한다. - 가용성
availability
: 분산 시스템에 접속하는 클라이언트는 일부 노드에 장애가 발생하더라도 항상 응답을 받을 수 있어야 한다. - 파티션 감내
partition tolerance
: 파티션은 두 노드 사이에 통신 장애가 발생함을 의미. 네트워크에 파티션이 생기더라도 시스템은 계속 동작하여야 한다.
- CP 시스템
일관성과 파티션 감내를 지원. 가용성을 희생 - AP 시스템
가용성과 파티션 감내를 지원. 데이터 일관성을 희생 - CA 시스템
일관성과 가용성을 지원. 파티션 감내는 지원하지 않는다. 네트워크 장애는 피할 수 없는 문제이므로 파티션 문제를 감내할 수 있도록 설계는 반드시 필요하다. (실세계에서는 존재하지 않음)
3.1.1 실세계의 분산 시스템
- 분산 시스템에서 파티션 문제는 피할 수 없으며 파티션 문제가 발생하면 우리는 일관성과 가용성 사이에 하나를 선택해야 한다.
CP 시스템(일관성)
- 세 서버 사이에 데이터 불일치 문제를 피하기 위해 n1, n2 쓰기 연산을 중단
- 가용성 깨짐
- 은행권 시스템등에서는 데이터 일관성이 중요
AP 시스템(가용성)
- 오래된 데이터를 반환하더라도 계속 읽기 연산을 허용
- n1, n2는 계속 쓰기 연산을 허용
- 파티션 문제 해결 후 n3에 새로운 데이터를 전송하여 동기화
3.1.2 컴포넌트
- 데이터 파티션
- 데이터 다중화
replication
- 일관성
consistency
- 일관성 불일치 해소
inconsistency resolution
- 장애 처리
- 시스템 아키텍처 다이어그램
- 쓰기 경로
write path
- 읽기 경로
read path
3.1.2 데이터 파이션
- 데이터를 작은 파티션으로 분할한 다음 여러대 서버에 저장한다.
- 데이터를 고르게 분산할 수 있는지 노드가 추가 및 삭제 되었을 때 데이터의 이동을 최소화 할 수 있는가
안정 해시를 사용하여 좋은점
- 규모 확정 자동화
automatic scaling
: 시스템 부하에 따라 서버가 자동으로 추가되거나 삭제 - 다양성
heterogeneity
: 각 서버 용량에 맞게 가상 노드의 수를 조정한다. 고성능 서버는 더 많은 가상 서버를 갖도록 설정 가능
3.1.3 데이터 다중화
- 높은 가용성과 안정성을 확보하기위해서는 데이터를 N개 서버에 비동기적으로 다중화
replication
할 필요가 있다.
3.1.4 데이터 일관성
- 여러 노드에 다중화 된 데이터는 적절히 동기화 되어야 한다.
- 정족수 합의
Quorum Consensus
프로토콜을 사용하면 읽기/쓰기 연산 모두에 일관성을 보장할 수 있다.
Note
- N = 사본개수
- W = 쓰기 연산에 대한 정족수. 쓰기 연산이 성공한 것으로 간주되러면 적어도 W개의 서버로부터 쓰기 연산이 성공했다는 응답을 받아야 한다.
- R = 읽기 연산에 대한 정족수. 읽기 연산이 성공한 것으로 간주되려면 적어도 R개의 서버로부터 응답을 받아야 한다.
- 중재자
coordinator
는 최소 한대 서버로부터 쓰기 응답을 받아야 한다는 뜻 s1
으로부터 성공 응답을 받았다면s0
,s2
로 부터 응답은 기다릴 필요가 없다.- 중재자는 클라이언트와 노드 사이에 프락시 역할을 한다.
W
,R
,N
의 값을 정하는 것은 응답 지연과 데이터 일관성 사이의 타협점을 찾는 전형적인 과정
N
, W
, R
값을 결정하는 방법
요구되는 일관성 수준에 따라 각각의 값을 정하면 된다.
R=1, W=N
: 빠른 읽기 연산에 최적화W=1, R=N
: 빠른 쓰기 연산에 최적화W+R > N
: 강한 일관성이 보장됨W+R <= N
: 강한 일관성이 보장되지 않음
일관성 모델
- 키-값 저장소를 설계할 때 고려해야할 또 다른 요소
- 강한 일관성
strong consistency
: 모든 읽기 연산은 최근에 갱신된 결과를 반환. 오래된out of date
데이터는 보지 못함 - 약한 일관성
weak consistency
: 읽기 연산은 최근에 갱신된 결과를 반환하지 못할 수 있음 - 결과적 일관성
eventual consistency
: 약한 일관성의 한 형태 갱신 결과가 결국에는 모든 사본에 반영(즉, 동기화) 되는 모델 - 강한 일관성을 유지하기 위해서는 모든 사본에 현재 쓰기 연산의 결과가 반영될 때 까지 해당 데이터에 대한 읽기/쓰기를 금지 -> 고가용성 시스템에는 적합하지 못함
- 다이나모 또는 카산드라 같은 경우 결과적 일관성 모델을 선택
- 연산이 병렬적으로 발생하면 시스템에 저장된 값의 일관성이 깨질 수 있다.
- 일관성이 깨지는 문제는 클라이언트가 해결해야 한다.
비 일관성 해소 기법 : 데이터 버저닝
- 버저닝
versioning
과 벡터시계vector colock
는 사본 간 일관성이 깨지는 문제를 해소화하기 위해 등장한 기술 - 버저닝은 데이터를 변경할 때 마다 해당 데이터 새로운 버전 생성한다. 각 버전은 변경 불가능
immutable
- 두 버전간 충돌을 발견하고 자동으로 해결해내기 위해 베터 시계가 보편적으로 사용되는 기술
- 벡터 시계는 [서버, 버전]의 순서쌍을 데이터에 매단 것이며 어떤 버전이 선행 혹은 후행인지 충돌이 있는지 판별
구체적인 사례
- 클라이언트가 데이터
D1
기록. 쓰기연산을Sx
가 처리 : D1[Sx, 1] - 다른 클라이언트가
D1
을 읽고D2
로 업데이트Sx
를 통해 기록. : D2[Sx, 2] - 다른 클라이언트가
D2
을 읽고D3
로 업데이트Sy
를 통해 기록. : D3[Sx, 2][Sy, 1] - 또 다른 클라이언트가
D2
를 읽고D4
로 업데이트Sz
를 통해 기록. : D4[Sx, 2][Sz, 1] - 어떤 클라이언트가
D3
,D4
를 읽으면 데이터 간 출돌이 있다는 것을 알게됨. 충돌은 클라이언트가 해소 후Sx
을 통해 기록. : D5[Sx, 3][Sy, 1][Sz, 1]
벡터 시계의 단점
- 충돌 감지 및 해소 로직이 클라이언트에 들어가야 하므로 클라이언트는 구성이 복잡
- 순서쌍 개수가 굉장히 빨리 늘어남. 이를 해소하기 위해서는 임계치를 설정하고 임계치 이상으로 길어지면 오래된 순서쌍을 벡터 시계에 제거
장애 감지failure detection
- 모든 노드 사이에 멀티 캐스팅
multicasting
채널을 구축하는 것이 손쉬운 방법이지만 서버가 많은때는 비효율적 - 가십 프로토콜
gossip protocol
같은 분산형 장애 감지decentralized failure detection
솔루션을 채택하는 것이 효율적
가십프로토콜의 동작 원리
- 각 노드는 멤버십 목록을 유지하며 멤버십 목록은 멤버의 ID와 박동 카운터
heartbeat counter
쌍의 목록 - 주기적으로 자신의 박동 카운터를 증가
- 각 노드는 무작위로 선정된 노드들에게 주기적으로 자기 박동 카운터 목록을 보냄
- 박동 카운터 목록을 받은 노드는 멤버십 목을 최신으로 갱신
- 어떤 멤버의 박동 카운터 값이 지정된 시간 동안 갱신 되지 않으면 해당 멤버는 장애 상태로 간주
일시적 장애 처리
- 가십 프로토콜로 장애를 감지한 시스템은 가용성 보장을 위해 필요한 조치를 해야 한다.
- 엄격한 정족수
strict quorum
접근법을 쓴다면 앞서 데이터 일관성 절에서 설명한 대로 읽기와 쓰기 연산을 금지 - 느슨한 정족수
sloppy quorum
접근법은 조건을 완하하여 가용성을 높인다.- 임시 위탁
hinted handoff
기법 - 정족수 요구성을 강제 대신 쓰기 연산을 수행할 W개의 건강한 서버와 읽기 연산을 R개의 건강한 서버를 해시 링에서 고른다.
- 네트워크 문제로 장애 상태인 서버는 다른 서버가 잠시 맡아 처리
- 해당 서버가 복구되었을 때 일관성을 반영하여 데이터 일관성을 보존한다.
- 임시로 쓰기 연산을 처리한 서버에는 단서
hint
를 남겨둔다
- 임시 위탁
영구적인 장애 처리
- 반-엔트로피
anti-entropy
프로토콜을 구현하여 사본들을 동기화 - 반-엔트로피 프로토콜은 사본들을 비교하여 최신 버전으로 갱신하는 과정을 포함
- 사본간 일관성이 망가진 상태를 탐지 전송 데이터의 양을 줄이기 위해서 머클
Merkle
트리를 사용한다.
머클 트리
- 노드에 그 자식 노드들에 보관된 해시(자식 노드가 종단 노드일 경우), 또는 자식 노드들의 레이블로부터 계산된 해시 값을 레이블로 붙이는 트리
- 대규모 자료구조 내용을 효과적이면서 보안상 안전한 방법으로 검증 가능
- 두 머클 트리의 비교는 루트 노드의 해시값을 비교하는 것을 시작으로 왼쪽 자식 노드의 해시값을 비교 그 다음 오른쪽 해시값을 비교하여 아래쪽으로 탐색하여 비교한다.
- 아래쪽으로 탐색하다가 다른 데이터를 갖는 버킷을 찾을 수 있으므로 그 버킷만 동기화 하면 된다.
데이터 센터 장애 처리
- 데이터 센터 장애에 대응할 수 있는 시스템을 만들려면 데이터를 여러 데이터 센터에 다중화 하는 것이 중요
3.1.5 시스템 아키텍처 다이어그램
- 클라이언트는 키-값 저장소가 제공하는 두 가지 단순한 API, 즉
get(key)
와put(key, value)
와 통신한다. - 중재자
coordinator
는 클라이언트에게 키-값 저장소에 대한proxy
역할을 하는 노드다 - 노드는 안정해시
consistent hash
의 해시 링 위에 분포 - 노드를 자동으로 추가 또는 삭제할 수 있도록, 시스템은 완전히 분산
- 데이터는 여러 노드에 다중화
- 모든 노드가 같은 책임을 지므로 SPOF 는 존재하지 않음
쓰기 경로
- 쓰기 요청이 커밋 로그 파일에 기록
- 데이터가 메모리 캐시에 기록
- 메모리 캐시가 가득차거나 임계치에 도달하면 데이터는 디스크에있는
SSTable
에 기록
- SSTable은 Sorted-String Table의 약어로 <키, 값>의 순서쌍을 정렬된 리스트 형태로 관리
읽기 경로
- 데이터가 메모리에 있는지 검사
- 데이터가 메모리에 없으면 블룸 필터를 검사
- 블룸 필터를 통해 어떤 SStable에 키가 보관되어 있는지 알아낸다
- SSTable 데이터를 가져온다.
- 해당 데이터를 클라이언트에 반환