Lamport Clock
Understanding logical time — how distributed systems order events without synchronized clocks.
Clocks Don't Agree in Distributed Systems
Physical clocks on different machines drift apart. Even with NTP synchronization, clocks can differ by milliseconds — enough to mis-order events. Two processes might each think their event happened first.
We need a way to order events that doesn't rely on physical time.
- Clock drift is inevitable (different crystal frequencies)
- NTP helps but doesn't guarantee perfect sync
- Network delays add uncertainty
- Need logical ordering, not physical timestamps
Forget Wall Clocks — Use Counters
Leslie Lamport's insight (1978): We don't need to know the actual time. We only need to know which events could have caused which other events — the "happens-before" relation.
A simple integer counter per process is enough to capture causality.
- Lamport clock: Integer counter starting at 0
- Each process maintains its own counter
- Counter only increases (never decreases)
- Captures the "happens-before" relationship
Increment, Attach, Max+1
The Lamport clock algorithm has three simple rules:
- Rule 1 — Local event: Increment your counter before each event
- Rule 2 — Send message: Attach your current counter value
- Rule 3 — Receive message: Set counter to
max(local, received) + 1
These rules ensure that if event A causally precedes event B, then clock(A) < clock(B).
Watch the Clocks Tick
Process A performs a local event (clock goes to 1), then sends a message
(clock goes to 2). Process B, with clock at 0, receives the message with
timestamp 2. It calculates
max(0, 2) + 1 = 3.
Now any event after the receive on B has clock > 2, preserving the ordering: send happened before receive.
- Send is an event itself: A's clock becomes 2
- Receive calculates max(local, msg)+1 = 3
- Causal chain: send → receive maintained
- B's subsequent events continue from 3
Causality Goes One Way
Lamport clocks have a key limitation: if clock(A) < clock(B), we only know A might have caused B. We cannot conclude A definitely caused B — they might be concurrent (causally independent).
-
clock(A) < clock(B)→ A happened-before B OR concurrent clock(A) = clock(B)→ definitely concurrent- Cannot distinguish causation from coincidence
- Vector clocks solve this (one counter per process)