Foundry
키-값 저장소 설계
중급
핵심

요구사항과 포기할 것 정하기

분단 중에 쓰기를 받으면 리더를 둘 수 없다

키-값 저장소는 기능이 두 개뿐입니다. 값을 넣고 꺼내는 것입니다. 기능이 단순한 만큼 설계는 비기능 요구사항이 전부 정합니다.

항목
대상분산 키-값 저장소
데이터100TB
노드300대
쓰기초당 10만
읽기초당 50만
값 크기평균 1KB
읽기 지연상위 1퍼센트가 10ms 이내
분단이 생기면쓰기를 계속 받는다
견뎌야 하는 장애노드 두 대가 동시에 죽어도 데이터가 남는다
응답한 쓰기노드가 죽어도 사라지지 않는다

기능 요구사항과 범위 밖

구분내용
이번에 만든다키로 값 넣기, 키로 값 꺼내기, 사본 유지, 노드 추가와 제거
범위 밖여러 키를 묶는 트랜잭션, 키 범위 조회, 값 내용 검색, 두 번째 인덱스, 서버가 두 값 중 최신을 골라 주는 것

범위 밖이 이 설계에서 특히 중요합니다. 여러 키를 묶는 트랜잭션을 빼면 노드 사이 합의가 필요 없어지고, 그것이 아래의 모든 선택을 가능하게 합니다. 하나만 남겨 두었다면 설계가 완전히 달라집니다.

분단 중에 쓰기를 받는다는 결정

분단이 생기면 리더가 있는 구조는 한쪽이 쓰기를 못 하고 리더가 없는 구조는 양쪽이 받는다 리더가 있으면 리더 쪽 반대쪽 리더 쪽만 쓰기를 받는다 반대쪽 사용자는 쓰기를 못 한다 리더가 없으면 한쪽 다른 쪽 양쪽이 쓰기를 받는다 같은 키에 두 값이 생길 수 있다 요구사항이 분단 중에도 쓰기를 받으라고 했다 그래서 두 값이 생기는 것을 받아들이고 나중에 정리한다 고른 것은 가용성, 낸 값은 충돌 해소라는 새 숙제다

네트워크가 갈라졌을 때 쓰기를 계속 받으려면 양쪽이 각자 받아야 합니다. 리더가 한쪽에 있으면 반대쪽 사용자는 쓰기를 할 수 없습니다.

그래서 이 요구사항은 리더가 없는 구조를 강제합니다. 어느 사본이든 쓰기를 받을 수 있고, 사본끼리 나중에 맞춥니다.

낸 값이 있습니다. 같은 키에 서로 다른 값이 생길 수 있고, 그것을 정리하는 일이 새 숙제가 됩니다. 고른 것과 낸 값을 함께 말하는 것이 이 결정을 설명하는 방법입니다.

숫자가 정하는 것

조건강제하는 것
100TB 를 300대 에키를 나눠 담아야 한다. 나누는 방법은 안정 해시 설계에서 다뤘다
쓰기 초당 10만, 값 평균 1KB초당 100MB. 제자리를 찾아 고치는 방식은 디스크가 못 따라온다
두 대 동시 사망 견디기사본이 셋 이상이어야 한다
응답한 쓰기 유실 불가응답하기 전에 디스크에 남겨야 한다
읽기 10ms값을 찾느라 파일 여러 개를 뒤지는 비용을 줄여야 한다

사본이 셋인 이유

두 대가 동시에 죽어도 데이터가 남으려면 사본이 셋 이상이어야 합니다. 둘이면 두 대가 함께 죽을 때 그 데이터가 사라집니다.

셋보다 많이 두면 저장 비용이 그만큼 늘어납니다. 100TB 에 사본 셋이면 실제로 저장하는 양은 300TB 입니다. 요구사항이 두 대까지라고 정했으므로 셋에서 멈춥니다.

이 저장소가 하지 않는 것

리더가 없으므로 "가장 최근 값" 을 아무도 확정해 주지 않습니다. 읽는 쪽이 낡은 값을 볼 수 있고, 두 값이 함께 반환될 수도 있습니다.

이 성질을 응용에 알려야 합니다. 잔액이나 재고처럼 정확한 순서가 필요한 데이터는 이 저장소에 두지 않는 편이 낫습니다. 무엇을 담을 수 있는 저장소인지가 요구사항에서 이미 정해집니다.

면접에서 이렇게 나옵니다

Q.키-값 저장소 설계에서 요구사항을 어떻게 정리하시겠습니까

기능이 단순하므로 비기능과 범위 밖에 집중합니다.

구분내용
기능값 넣기, 값 꺼내기, 사본 유지, 노드 추가와 제거
범위 밖여러 키를 묶는 트랜잭션, 키 범위 조회, 값 검색, 두 번째 인덱스, 최신 판단
비기능100TB, 300대, 쓰기 초당 10만, 읽기 초당 50만, 읽기 10ms

가장 중요한 항목은 분단 중에도 쓰기를 받는다노드 두 대가 동시에 죽어도 데이터가 남는다입니다. 앞의 것이 구조를, 뒤의 것이 사본 수를 정합니다.

흔한 실수: 범위 밖을 말하지 않는 것. 여러 키를 묶는 트랜잭션 하나만 남겨도 노드 사이 합의가 필요해지고 아래의 모든 선택이 달라집니다. 무엇을 뺐는지가 이 설계에서는 특히 큰 차이를 만듭니다.

Q.분단 중에도 쓰기를 받으려면 무엇을 포기해야 하나요

리더를 포기하고, 같은 키에 두 값이 생기는 것을 받아들입니다.

네트워크가 갈라졌을 때 양쪽이 각자 쓰기를 받아야 합니다. 리더가 한쪽에 있으면 반대쪽 사용자는 쓰기를 할 수 없습니다.

리더가 있으면: 리더 쪽만 쓰기를 받는다
리더가 없으면: 양쪽이 받는다. 대신 값이 갈린다

그래서 어느 사본이든 쓰기를 받고 사본끼리 나중에 맞춥니다. 고른 것은 가용성이고 낸 값은 충돌 해소라는 새 숙제입니다.

흔한 실수: 가용성을 골랐다고만 말하고 대가를 말하지 않는 것. 면접에서는 곧바로 "그러면 같은 키에 두 값이 생기면 어떻게 하나요" 가 이어집니다. 선택과 대가를 한 문장에 담는 것이 이 결정을 이해했다는 신호입니다.

Q.사본을 몇 벌 두시겠습니까

셋입니다. 요구사항이 노드 두 대의 동시 사망을 견디라고 했기 때문입니다.

사본이 둘이면 두 대가 함께 죽을 때 그 데이터가 사라집니다. 셋이면 하나가 남습니다.

셋보다 많으면 저장 비용이 그만큼 늘어납니다. 100TB 에 사본 셋이면 실제 저장량이 300TB 입니다.

견뎌야 하는 동시 사망 대수 + 1 = 필요한 사본 수

요구사항이 두 대까지라고 정했으므로 셋에서 멈춥니다. 더 두는 것은 요구사항 없이 비용을 늘리는 일입니다.

흔한 실수: 사본 수를 관례로 정하는 것. 셋이 흔한 값이지만 이유는 요구사항에서 나와야 합니다. 랙이나 지역 단위 장애까지 견뎌야 한다면 사본 수뿐 아니라 배치 규칙도 함께 정해야 하고, 그 요구가 없으면 셋으로 충분합니다.

Q.이 저장소에 담기 어려운 데이터는 무엇인가요

정확한 순서나 즉시 일관성이 필요한 데이터입니다. 잔액과 재고가 대표적입니다.

리더가 없으므로 "가장 최근 값" 을 아무도 확정해 주지 않습니다. 읽는 쪽이 낡은 값을 볼 수 있고, 두 값이 함께 반환될 수도 있습니다.

잘 맞는 데이터맞지 않는 데이터
사용자 설정, 세션, 활동 기록잔액, 재고, 좌석 예약
마지막 쓰기만 의미 있는 값이전 값을 읽고 계산해 쓰는 값

이 성질을 응용에 알려야 합니다. 저장소가 감당하지 못하는 것을 응용이 모르면, 문제가 생겼을 때 원인을 저장소 장애로 오해합니다.

흔한 실수: 나중에 강한 일관성을 옵션으로 붙이겠다고 답하는 것. 리더가 없는 구조에서 강한 일관성은 읽기와 쓰기 모두를 느리게 만드는 별개의 설계입니다. 요구사항이 가용성을 골랐다면 그 대가를 응용과 나누는 편이 정직합니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

키-값 저장소 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.