Logical Clocks in Distributed Systems
Logical clocks let you order events in a distributed system without synchronized physical clocks. They track causality - “A happened before B” - which is what you usually care about anyway.
Lamport clocks are the simplest. Each node keeps a counter. Increment on local events, set to max(local, received)+1 when you get a message.
Node A: 1 → 2 → 3
↘ (sends msg with timestamp 2)
Node B: 1 --------→ 3 → 4
(receives, sets to max(1,2)+1=3)
If A’s timestamp is less than B’s, A might have happened before B. But equal timestamps or B < A doesn’t mean anything - the events could be concurrent. Lamport clocks give you a partial order, which is often enough.
Vector clocks give you more. Each node keeps a counter per node. When you send a message, include the whole vector. On receive, take the component-wise max.
VC(A) = [2, 1, 0]
VC(B) = [1, 2, 1]
Neither is strictly less than the other → A and B are concurrent
Now you can distinguish “happened before” from “concurrent.” The cost is O(n) space per event, where n is the number of nodes.
Hybrid logical clocks (HLCs) combine physical time with logical counters. You get causality tracking plus timestamps that roughly correspond to wall-clock time. Used in Spanner, CockroachDB - systems that want both ordering and human-readable timestamps.
The tradeoff is always space/complexity vs precision. Lamport clocks are tiny but imprecise. Vector clocks are precise but don’t scale to many nodes. HLCs are a practical middle ground for databases.