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

사본을 다시 맞추기

다른 곳만 찾아 그 구간만 주고받는다

사본이 어긋나는 경로가 앞에서 여러 개 나왔습니다. 쓰기가 셋 중 둘에만 성공하고, 죽어 있던 노드가 돌아오고, 분단 중 양쪽이 각자 씁니다. 어긋남은 예외가 아니라 상시 상태입니다.

그래서 맞추는 일을 설계에 넣습니다. 방법이 셋이고 비용과 시점이 다릅니다.

세 가지 시점

방법언제비용
읽는 김에 고치기그 키를 누가 읽을 때거의 없다. 이미 비교했다
돌아온 노드에 넘기기잠깐 죽었다 돌아올 때보관해 둔 만큼
배경에서 전부 맞추기주기적으로크다. 전체를 비교해야 한다

앞의 둘로 대부분이 해결됩니다. 그런데 아무도 읽지 않는 키는 앞의 둘로 절대 고쳐지지 않습니다. 조회가 없으면 읽는 김에 고칠 기회가 없고, 대신 받아 둔 것도 상한을 넘겨 버려졌을 수 있습니다.

그 키들이 남아 있는 상태에서 다른 사본이 죽으면 최신 값이 사라집니다. 그래서 배경에서 전부 맞추는 일이 필요합니다.

전부 비교하면 감당할 수 없다

노드당 담는 양이 크므로 두 사본이 키를 전부 주고받으면 네트워크가 감당하지 못합니다. 어긋난 키는 대개 아주 적은데 찾는 비용이 전체 크기에 비례하는 것이 문제입니다.

요약값을 위에서부터 비교해 다른 구간만 좁혀 찾는다 구간마다 요약값을 만들어 둔다 전체 앞 절반 뒤 절반 구간 3 구간 4 요약값이 다르다 앞 절반은 같다. 안 본다 구간 3 만 비교하면 된다 같은 구간은 요약값 하나로 확인하고 넘긴다 전부 주고받으면 노드당 수백 기가를 옮겨야 한다 다른 곳만 찾아 그 구간의 키만 주고받는다

키 범위를 구간으로 나누고 구간마다 요약값을 만들어 둡니다. 그 요약값들을 다시 묶어 위쪽 요약값을 만듭니다. 그러면 비교를 위에서부터 좁혀 갈 수 있습니다.

맨 위 요약값이 같으면 전부 같다. 끝난다
다르면 아래로 내려가 다른 쪽만 따라간다
같은 쪽은 요약값 하나로 확인하고 넘긴다

어긋난 키가 하나뿐이어도 찾는 데 필요한 비교는 몇 단계로 끝납니다. 전송량이 데이터 크기가 아니라 어긋난 양에 비례하게 됩니다.

요약값을 언제 다시 만드나

쓰기가 들어오면 그 구간의 요약값이 낡습니다. 매 쓰기마다 위쪽까지 다시 계산하면 쓰기 경로가 무거워집니다.

방식대가
쓰기마다 갱신쓰기가 무거워진다
파일을 합칠 때 갱신그 사이 요약값이 낡아 헛비교가 생긴다

합칠 때 함께 만드는 편이 낫습니다. 어차피 그때 파일 전체를 읽으므로 추가 비용이 작습니다. 헛비교가 조금 생기지만 맞추기는 주기 작업이라 급하지 않습니다.

맞추기가 서비스를 밀어내지 않게

배경 맞추기는 네트워크와 디스크를 씁니다. 파일 합치기와 마찬가지로 사용자 요청과 같은 자원을 다투므로 속도에 상한을 둡니다.

그리고 사본 셋이 동시에 맞추기를 시작하지 않게 흩습니다. 이유는 합치기와 같습니다. 셋이 함께 느려지면 읽기 정족수가 느린 사본을 우회할 수 없습니다.

이 설계가 약속하는 것

마지막으로 무엇을 약속하고 무엇을 약속하지 않는지 정리합니다.

약속한다약속하지 않는다
분단 중에도 쓰기를 받는다방금 쓴 값을 바로 읽는 것
두 대가 죽어도 데이터가 남는다두 값 중 어느 것이 최신인지 서버가 판단하는 것
언젠가 사본이 같아진다언제까지 같아지는지

약속하지 않는 것을 명확히 적는 것이 이 저장소를 쓰는 사람에게 가장 중요한 문서입니다. 모르고 쓰면 저장소 장애로 오해하고, 알고 쓰면 응용에서 감당할 수 있습니다.

면접에서 이렇게 나옵니다

Q.어긋난 사본을 어떻게 맞추시겠습니까

세 시점을 함께 씁니다. 값싼 것부터입니다.

방법언제비용
읽는 김에 고치기그 키를 누가 읽을 때거의 없다
돌아온 노드에 넘기기잠깐 죽었다 돌아올 때보관해 둔 만큼
배경에서 전부 맞추기주기적으로크다

앞의 둘로 대부분이 해결됩니다. 그런데 아무도 읽지 않는 키는 앞의 둘로 절대 고쳐지지 않습니다. 조회가 없으면 고칠 기회가 없고, 대신 받아 둔 것도 상한을 넘겨 버려졌을 수 있습니다.

그 키들이 남은 상태에서 다른 사본이 죽으면 최신 값이 사라집니다.

흔한 실수: 읽는 김에 고치기만으로 충분하다고 답하는 것. 조회가 없는 데이터가 가장 위험합니다. 문제가 조용히 쌓이고, 드러나는 순간은 데이터를 잃은 뒤입니다.

Q.두 사본의 차이를 어떻게 값싸게 찾나요

키 범위를 구간으로 나눠 요약값을 만들고, 위에서부터 좁혀 갑니다.

맨 위 요약값이 같으면 전부 같다. 끝난다
다르면 아래로 내려가 다른 쪽만 따라간다
같은 쪽은 요약값 하나로 확인하고 넘긴다

키를 전부 주고받으면 노드당 수백 기가를 옮겨야 합니다. 어긋난 키는 대개 아주 적은데 찾는 비용이 전체 크기에 비례하는 것이 문제였습니다.

요약값을 쓰면 전송량이 데이터 크기가 아니라 어긋난 양에 비례합니다.

흔한 실수: 구간을 너무 크게 잡는 것. 어긋난 키 하나 때문에 그 구간의 키 전체를 주고받게 됩니다. 구간 크기가 곧 찾는 정밀도와 요약값 개수의 균형점입니다.

Q.요약값을 언제 다시 만드시겠습니까

파일을 합칠 때 함께 만듭니다.

쓰기가 들어오면 그 구간의 요약값이 낡습니다. 매 쓰기마다 위쪽까지 다시 계산하면 쓰기 경로가 무거워집니다.

방식대가
쓰기마다 갱신쓰기가 무거워진다
합칠 때 갱신그 사이 요약값이 낡아 헛비교가 생긴다

합칠 때는 어차피 파일 전체를 읽으므로 추가 비용이 작습니다. 헛비교가 조금 생기지만 맞추기는 주기 작업이라 급하지 않습니다.

흔한 실수: 정확한 요약값을 늘 유지하려는 것. 쓰기 초당 10만 건에 매번 갱신하면 그 계산이 쓰기 경로의 병목이 됩니다. 급하지 않은 일을 정확하게 만들려고 급한 일을 느리게 하는 것이 흔한 잘못입니다.

Q.이 저장소가 약속하지 않는 것은 무엇인가요

방금 쓴 값을 바로 읽는 것, 최신 판단, 그리고 언제까지 같아지는지입니다.

약속한다약속하지 않는다
분단 중에도 쓰기를 받는다방금 쓴 값을 바로 읽는 것
두 대가 죽어도 데이터가 남는다두 값 중 어느 것이 최신인지 서버가 판단하는 것
언젠가 사본이 같아진다언제까지 같아지는지

특히 마지막이 중요합니다. 최종 일관성은 언젠가 같아진다는 약속일 뿐 기한을 말하지 않습니다.

약속하지 않는 것을 명확히 적는 것이 이 저장소를 쓰는 사람에게 가장 중요한 문서입니다.

흔한 실수: 약속을 좋게 들리게 적는 것. "높은 가용성과 최종 일관성" 이라고만 쓰면 쓰는 사람은 자기에게 필요한 보장이 있다고 가정합니다. 모르고 쓰면 문제를 저장소 장애로 오해하고, 알고 쓰면 응용에서 감당할 수 있습니다.

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

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

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