사본이 셋이라고 정했습니다. 그러면 새 질문이 생깁니다. 쓸 때 몇 개가 성공하면 성공이라고 할까요. 읽을 때 몇 개에서 받아야 할까요.
이 두 숫자가 일관성과 가용성과 지연을 함께 조절하는 손잡이입니다.
숫자 두 개
사본 수를 셋이라 하고, 쓰기에 필요한 성공 수와 읽기에 필요한 응답 수를 각각 정합니다.
쓰기 성공 수 + 읽기 응답 수 > 사본 수
이 관계가 성립하면 읽을 때 받는 응답 중 최소 하나는 최신 쓰기를 받은 사본입니다. 셋 중 둘에 썼고 셋 중 둘에서 읽으면, 둘과 둘은 겹치지 않을 수 없습니다.
| 조합 | 성질 |
|---|---|
| 쓰기 1, 읽기 1 | 가장 빠르다. 최신 값을 만난다는 보장이 없다 |
| 쓰기 2, 읽기 2 | 최신 값을 만난다. 한 대가 죽어도 동작한다 |
| 쓰기 3, 읽기 1 | 읽기가 매우 빠르다. 한 대만 죽어도 쓰기가 실패한다 |
가용성 요구가 조합을 좁힌다
요구사항이 분단 중에도 쓰기를 받으라고 했습니다. 쓰기에 셋을 요구하면 한 대만 죽어도 쓰기가 실패하므로 그 요구를 어깁니다.
그래서 쓰기는 둘, 읽기는 둘로 둡니다. 한 대가 죽어도 양쪽 모두 동작하고 최신 값도 만납니다.
기다리는 수가 꼬리 지연을 정한다
셋에 모두 보내고 둘의 응답만 기다립니다. 그러면 마침 바쁜 사본 하나를 버릴 수 있습니다.
이것이 정족수의 덜 알려진 이득입니다. 규모가 커지면 어느 순간에도 몇 대는 느립니다. 셋을 다 기다리면 가장 느린 하나가 매 요청의 지연을 정합니다. 읽기 10ms 요구를 지키는 데 이 성질이 결정적입니다.
그래도 최신을 보장하지 못하는 경우
쓰기 둘, 읽기 둘이어도 어긋나는 상황이 남습니다.
| 상황 | 무슨 일이 생기나 |
|---|---|
| 쓰기가 둘에 실패하고 하나만 성공 | 실패로 응답했는데 그 하나에는 값이 남는다 |
| 두 쓰기가 동시에 다른 사본에 도달 | 사본마다 순서가 다르게 보인다 |
| 분단 중 양쪽이 각자 둘을 채움 | 겹치지 않는 두 정족수가 생긴다 |
정족수는 최신 값을 만날 확률을 높이는 장치이고, 순서를 정해 주지는 않습니다. 순서를 정하려면 리더가 필요한데 이 설계는 리더를 포기했습니다. 그래서 다음 단계에서 값이 갈렸을 때 무엇을 최신으로 볼지 정합니다.
응용마다 다르게 줄 수 있다
이 두 숫자는 요청마다 바꿀 수 있습니다. 세션 정보는 쓰기 하나로 빠르게 쓰고, 사용자 설정은 쓰기 둘로 안전하게 쓰는 식입니다.
한 저장소 안에서 데이터마다 다른 값을 주는 것이 이 방식의 큰 장점입니다. 다만 응용이 그 뜻을 알아야 하고, 모르고 쓰면 어떤 데이터는 이유 없이 낡은 값을 보게 됩니다.