앞 단계에서 정족수가 순서를 정해 주지 않는다는 것을 봤습니다. 리더가 없으니 같은 키에 값이 둘 생길 수 있고, 이제 무엇을 최신으로 볼지 정해야 합니다.
시각으로 고르면 조용히 하나가 사라진다
가장 단순한 방법은 시각이 늦은 값을 이기게 하는 것입니다. 구현이 쉽고 값이 하나로 정해집니다.
문제는 두 쓰기가 같은 이전 값을 보고 시작한 경우입니다. 위 그림에서 한 쪽은 배를, 다른 쪽은 우유를 담았습니다. 시각으로 하나를 고르면 다른 하나가 사라지고, 사용자는 담은 물건이 없어졌다고 느낍니다.
그리고 시각 자체를 믿기 어렵습니다. 노드마다 시계가 조금씩 다르므로 먼저 쓴 값이 늦은 시각을 가질 수 있습니다.
| 방식 | 결과 |
|---|---|
| 시각이 늦은 값이 이긴다 | 값이 하나로 정해진다. 한쪽이 조용히 사라진다 |
| 무엇을 보고 썼는지 기록한다 | 충돌을 알아챌 수 있다. 정리 책임이 응용에 간다 |
무엇을 보고 썼는지 기록한다
값을 줄 때 그 값의 표시를 함께 주고, 쓸 때 그 표시를 되돌려 받습니다. 그러면 서버가 이 쓰기가 어느 값을 보고 만들어졌는지 알 수 있습니다.
읽기: 값 v1 과 함께 표시를 준다
쓰기: 새 값과 v1 표시를 함께 보낸다
서버: v1 뒤에 이미 다른 값이 있으면 충돌이다
충돌이면 두 값을 모두 보관하고 다음 읽기에서 함께 돌려줍니다. 그것을 어떻게 합칠지는 응용이 압니다. 장바구니라면 합집합을 취하면 되고, 설정값이라면 사용자에게 물어야 할 수도 있습니다.
알아채는 것이 고르는 것보다 중요하다
이 설계의 핵심은 충돌을 없애는 것이 아닙니다. 리더가 없으니 충돌은 생깁니다. 알아채지 못하는 것이 문제입니다.
| 상황 | 사용자가 겪는 일 |
|---|---|
| 충돌을 모르고 하나를 버림 | 담은 물건이 이유 없이 사라진다 |
| 충돌을 알고 합침 | 둘 다 남는다 |
| 충돌을 알고 물어봄 | 잠깐 번거롭지만 잃지 않는다 |
조용한 유실이 가장 나쁩니다. 사용자는 원인을 모르고, 우리도 지표에서 볼 수 없습니다.
그래도 시각으로 고르는 경우
값이 갈릴 일이 없거나, 갈려도 하나를 버려도 되는 데이터라면 시각 방식이 낫습니다.
마지막 상태만 의미 있는 값: 위치, 온도, 조회 수 갱신
이전 값을 읽고 계산해 쓰는 값: 장바구니, 잔액, 목록 편집
앞쪽은 시각으로 충분합니다. 뒤쪽에서 시각을 쓰면 사용자가 편집한 내용이 사라집니다. 데이터의 성격이 방식을 정합니다.
보관하는 값이 늘어나는 문제
충돌을 보관하면 값이 쌓입니다. 응용이 합쳐 주지 않으면 계속 늘어나므로, 합친 결과를 다시 써서 이전 것들을 정리하게 만들어야 합니다.
그리고 삭제가 어려워집니다. 값을 지우기만 하면 다른 사본에 남아 있던 옛 값이 되살아납니다. 그래서 삭제도 하나의 값으로 기록합니다. 다음 단계의 저장 구조가 이 성질과 맞물립니다.