칸을 나눠 쓰는 방식은 유일성을 구조로 보장합니다. 단 전제가 둘 있습니다. 노드 번호가 겹치지 않는 것과, 시각이 뒤로 가지 않는 것입니다. 이 절은 뒤쪽 전제를 다룹니다.
시계는 실제로 뒤로 간다
| 원인 | 상황 |
|---|---|
| 시각 동기화 보정 | 시계가 앞서 있었으면 뒤로 당긴다 |
| 가상 머신 정지와 복귀 | 멈춘 동안 시각이 어긋난다 |
| 사람의 수동 변경 | 운영 중 실수로 바꾼다 |
드문 일이지만 반드시 일어납니다. 노드 64대 를 수년 운영하면 겪습니다.
뒤로 가면 무엇이 잘못되나
시각이 ID의 일부이므로 시계가 뒤로 가면 이미 발급에 쓴 시각 구간을 다시 씁니다. 그 시각의 순번이 아직 쓰지 않은 값이면 우연히 괜찮지만, 이미 쓴 순번과 겹치면 같은 ID가 두 번 나옵니다.
중복은 되돌릴 방법이 없습니다. 두 데이터가 하나로 취급되고, 그 사실을 나중에 알아채기도 어렵습니다.
마지막으로 쓴 시각을 기억한다
대응의 출발점은 하나입니다. 자기가 발급에 쓴 가장 큰 시각을 들고 있는 것입니다. 새 발급에서 현재 시각이 그보다 작으면 되돌림을 감지합니다.
| 되돌린 폭 | 대응 |
|---|---|
| 몇 밀리초 | 따라잡을 때까지 기다린다 |
| 그보다 크면 | 발급을 거부하고 경보를 올린다 |
거부가 맞는 이유는 요구사항에 있습니다. 유일성은 절대 포기하지 않는다고 정했습니다. 발급 실패는 재시도로 회복되지만 중복은 회복되지 않습니다. 회복 가능한 실패를 골라야 합니다.
재시작하면 기억이 사라진다
프로세스가 다시 뜨면 마지막 시각 기억이 없습니다. 그때 시계가 뒤로 가 있으면 감지하지 못합니다.
마지막으로 쓴 시각을 주기적으로 디스크나 외부에 남긴다
재시작할 때 그 값을 읽어 비교한다
남기는 주기가 곧 보호 범위입니다. 1초마다 남기면 최악의 경우 1초분을 놓칩니다. 쓰기 비용과 보호 범위의 균형점으로 정합니다.
순서 문제와 구분한다
시계를 순서의 근거로 쓰면 안 된다는 이야기는 다른 곳에서도 나옵니다. 그런데 문제의 성질이 다릅니다.
| 상황 | 시계가 틀리면 |
|---|---|
| 시계로 순서를 정할 때 | 순서가 뒤바뀐다. 보이는 결과가 어색하다 |
| 시계가 ID 의 일부일 때 | 중복이 생긴다. 데이터가 섞인다 |
같은 원인이 훨씬 나쁜 결과를 만듭니다. 그래서 여기서는 시계를 감시 대상으로 두고 발급 경로에서 직접 검사합니다.