Foundry
키-값 저장소 설계
심화
핵심

쓰기 경로와 내구성

덮어쓰지 않고 끝에 붙인다

쓰기 초당 10만 에 값 평균 1KB 이면 초당 100MB 입니다. 그리고 응답한 쓰기는 노드가 죽어도 남아야 합니다. 이 두 조건이 쓰기 경로를 정합니다.

제자리를 고치면 못 따라온다

키가 무작위로 흩어져 있으므로 제자리를 찾아 고치는 방식은 매번 다른 위치를 다뤄야 합니다. 디스크에서 흩어진 위치를 찾아다니는 것은 순서대로 쓰는 것보다 훨씬 느립니다.

초당 10만 건을 받으려면 디스크에 순서대로만 써야 합니다.

끝에 붙이고 메모리에 모은다

기록을 끝에 붙이고 메모리에 모아 두었다가 한꺼번에 정렬해 내려쓴다 쓰기 한 건이 지나는 길 기록 파일 끝에 붙인다 메모리 표 정렬해 모은다 정렬 파일 한꺼번에 응답은 첫 칸에서 응답 전에 기록 파일에 남으므로 죽어도 복구된다 디스크에는 순서대로만 쓴다. 흩어진 곳을 찾아가지 않는다 제자리를 고치면 키마다 흩어진 위치를 찾아가 고친다. 초당 10만은 못 낸다 덮어쓰지 않고 새 값을 덧붙인다. 옛 값은 나중에 치운다 그래서 삭제도 지우는 것이 아니라 삭제 표시를 덧붙이는 것이다

쓰기가 오면 먼저 기록 파일 끝에 붙입니다. 이것은 순차 쓰기라 빠르고, 디스크에 남았으므로 노드가 죽어도 복구할 수 있습니다. 여기까지 되면 응답합니다.

그다음 메모리의 표에 넣어 정렬 상태로 모아 둡니다. 표가 어느 크기에 이르면 한꺼번에 정렬된 파일로 내려씁니다. 이것도 순차 쓰기입니다.

단계성질
기록 파일에 붙이기순차. 응답의 근거가 된다
메모리 표에 넣기빠르다. 죽으면 사라진다
정렬 파일로 내려쓰기순차. 한꺼번에

응답의 근거는 기록 파일입니다. 메모리에만 있는 상태에서 응답하면 노드가 죽을 때 그 쓰기가 사라지고, 요구사항을 어깁니다.

덮어쓰지 않는다

같은 키를 다시 쓰면 옛 값을 찾아 고치지 않고 새 값을 덧붙입니다. 읽을 때 가장 새 것을 고릅니다.

그래서 삭제도 지우는 것이 아니라 삭제 표시를 덧붙이는 것입니다. 앞 단계에서 삭제가 하나의 값이어야 한다고 한 이유와 여기서 맞물립니다.

이 구조가 만드는 대가가 있습니다. 같은 키의 옛 값들이 파일에 남아 공간을 차지하고, 읽을 때 여러 파일을 봐야 합니다. 그 대가를 뒤의 두 단계에서 다룹니다.

기록 파일을 언제까지 두나

메모리 표가 정렬 파일로 내려가면 그 구간의 기록 파일은 더 필요 없습니다. 지우지 않으면 디스크가 찹니다.

정렬 파일로 내려쓰기가 끝나면 그 앞의 기록 파일을 버린다
버리기 전에 내려쓰기가 확실히 끝났는지 확인한다

순서를 거꾸로 하면 복구할 수 없는 구간이 생깁니다. 이런 실수는 평소에 드러나지 않고 노드가 죽을 때만 드러납니다.

사본 셋에 어떻게 쓰나

앞 단계에서 쓰기 성공 수를 둘로 정했습니다. 세 사본에 모두 보내고 둘이 기록 파일에 남겼다고 응답하면 성공으로 봅니다.

나머지 하나는 늦게 받거나 못 받을 수 있습니다. 그 사본을 어떻게 따라잡게 할지가 장애 처리 단계의 주제입니다.

면접에서 이렇게 나옵니다

Q.쓰기 초당 10만 을 어떻게 받으시겠습니까

디스크에 순서대로만 씁니다. 제자리를 찾아 고치지 않습니다.

키가 무작위로 흩어져 있으므로 제자리 갱신은 매번 다른 위치를 다뤄야 합니다. 흩어진 위치를 찾아다니는 것은 순차 쓰기보다 훨씬 느립니다.

1. 기록 파일 끝에 붙인다. 순차 쓰기
2. 메모리 표에 넣어 정렬 상태로 모은다
3. 표가 차면 한꺼번에 정렬 파일로 내려쓴다. 순차 쓰기

디스크가 하는 일이 전부 순차 쓰기이므로 초당 10만 건을 받을 수 있습니다.

흔한 실수: 메모리에 넣은 뒤 바로 응답하는 것. 그러면 노드가 죽을 때 그 쓰기가 사라져 응답한 쓰기가 유실되지 않아야 한다는 요구사항을 어깁니다. 응답의 근거는 기록 파일입니다.

Q.같은 키를 다시 쓰면 옛 값은 어떻게 되나요

남습니다. 덮어쓰지 않고 새 값을 덧붙이기 때문입니다.

읽을 때 가장 새 것을 고릅니다. 그래서 삭제도 지우는 것이 아니라 삭제 표시를 덧붙이는 것입니다.

키 A 에 값 1 을 쓴다
키 A 에 값 2 를 쓴다. 값 1 은 그대로 남는다
키 A 를 지운다. 삭제 표시가 덧붙는다

대가가 둘 있습니다. 옛 값이 공간을 차지하고, 읽을 때 여러 파일을 봐야 합니다.

흔한 실수: 덧붙이기 구조에서 공간이 계속 늘어나는 것을 언급하지 않는 것. 파일 합치기가 반드시 따라와야 하는 구조이고, 그것을 말하지 않으면 절반만 설계한 것입니다.

Q.기록 파일을 언제 버리시겠습니까

메모리 표가 정렬 파일로 내려간 것이 확실해진 뒤입니다.

정렬 파일 내려쓰기 완료를 확인한다
그 구간에 해당하는 기록 파일을 버린다

순서를 거꾸로 하면 복구할 수 없는 구간이 생깁니다. 메모리에만 있던 데이터가 사라지고 기록 파일도 없는 상태입니다.

버리지 않으면 디스크가 계속 찹니다. 초당 100MB 를 받는 시스템에서 기록 파일은 하루에 8TB 이상 쌓입니다.

흔한 실수: 이 실수의 성질을 모르는 것. 순서를 거꾸로 해도 평소에는 아무 증상이 없습니다. 노드가 죽었을 때만 데이터가 사라져 있고, 그때는 원인을 찾기 어렵습니다.

Q.사본 셋에는 어떻게 쓰나요

셋에 모두 보내고 둘이 기록 파일에 남겼다고 응답하면 성공으로 봅니다.

앞 단계에서 쓰기 성공 수를 둘로 정했습니다. 여기서 중요한 것은 각 사본에서 성공의 뜻입니다.

어디까지 되면 성공인가결과
기록 파일에 남았다그 노드가 죽어도 복구된다
메모리 표에 들어갔다그 노드가 죽으면 사라진다

둘이 기록 파일에 남겼으면 노드 하나가 죽어도 데이터가 있습니다.

흔한 실수: 나머지 한 사본을 어떻게 따라잡게 할지 말하지 않는 것. 늦게 받거나 못 받은 사본이 계속 낡은 채 남으면 나중에 그 사본에서 읽을 때 옛 값이 나옵니다. 정족수는 그 순간을 넘기는 장치이고 따라잡기는 별도 설계입니다.

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

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

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