Time
- 5.1 Physical clocks
- 5.2 Logical clocks
- 5.3 Vector clocks
분산 시스템에서 "이 연산이 저 연산보다 먼저 일어났어?"라는 질문은 생각보다 훨씬 어려워. 단일 프로세스면 실행 순서가 자명하잖아. 근데 분산 시스템에는 모든 프로세스가 동의하는 공유 글로벌 시계가 없고, 프로세스는 동시에 돌아가. 이 장은 그 "순서"를 어떻게 정하냐는 이야기야.
**물리적 시계(physical clock)**부터 보자. 대부분 쿼츠 크리스탈 기반인데, 싸지만 정확하지 않아. 제조 차이, 온도에 따라 시계마다 속도가 조금씩 달라 — 이게 **클럭 드리프트(clock drift)**야. 특정 시점에서 두 시계 차이가 **클럭 스큐(clock skew)**고. 이걸 보정하려고 **NTP(Network Time Protocol)**로 원자 시계에 동기화하는데, NTP가 시계를 앞이나 뒤로 점프시킬 수 있어. 연산 A 다음에 B가 실행됐는데 시계 점프 때문에 B의 타임스탬프가 더 이른 경우가 생기는 거야. **단조 시계(monotonic clock)**는 부팅 이후 경과한 시간만 재니까 점프는 없지만, 같은 노드 안에서만 의미가 있어. 결론? 물리적 시계로는 다른 프로세스 이벤트의 순서를 정확히 정할 수 없어.
그래서 **논리 시계(logical clock)**가 나와. 벽시계 시간이 아니라 논리적 연산 단위로 시간을 측정하는 거야. Lamport clock이 가장 기본인데, 카운터를 0으로 시작해서 연산마다 1씩 올리고, 메시지 보낼 때 카운터를 포함시키고, 받을 때 받은 카운터와 로컬 카운터의 최댓값을 취한 뒤 1을 올려. 이 규칙이 보장하는 건 — A가 B 이전에 발생했다면(happened-before), A의 타임스탬프가 B보다 작다는 거야. 근데 역은 안 돼. 타임스탬프가 더 작다고 반드시 먼저 발생한 건 아니야. 인과 관계를 정확히 추적하려면 뭔가 더 필요해.
그게 **벡터 시계(vector clock)**야. 프로세스가 3개면 각각 [P1, P2, P3] 카운터 배열을 유지해. 연산 시 자기 카운터만 올리고, 메시지 보내면 배열 사본을 포함시키고, 받으면 각 요소의 최댓값을 취하고 자기 카운터를 올려. 두 타임스탬프를 비교할 때 T1의 모든 카운터가 T2 이하이고 하나라도 작으면 T1이 먼저 발생한 거야. 어느 쪽도 다른 쪽 이전이 아니면? 두 연산은 **동시적(concurrent)**이야. 이건 Lamport 시계로는 감지 못 하는 정보지. 단점은 프로세스 수에 비례해 공간이 늘어난다는 것이고, dotted version vectors 같은 변형으로 최적화할 수 있어.
정리
5장 읽고 기억할 거 세 가지:
- 물리적 시계는 분산 이벤트 순서를 정확히 결정 못 해 — NTP 동기화에도 클럭 드리프트와 점프가 존재하거든.
- Lamport clock은 happened-before를 순방향으로만 보장하고, Vector clock은 역방향도 보장해 — 타임스탬프만으로 인과 관계를 확정할 수 있어.
- Vector clock은 동시성(concurrency)도 감지할 수 있어 — 이건 나중에 CRDT와 인과적 일관성의 기초가 돼.