CMD Guide
HomeSystem DesignMental Models & Systems Thinking

Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime

Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime

Almost every hard problem in distributed systems reduces to one question: in what order did these events happen? Which write is newer? Did this read observe that write? Was the lock released before it was re-acquired? On a single machine you answer with a clock. Across machines, the naive move — stamp each event with the local wall-clock time and sort — is wrong, and it fails silently. This page builds ordering from first principles: why physical time betrays you, what logical time captures instead, and the ladder of clocks (Lamport → vector → hybrid logical → TrueTime) that trades metadata, hardware, and latency for stronger ordering guarantees.

Mechanism first: why you cannot order distributed events by wall-clock time

A wall clock (the "time of day", NTP-disciplined) is an estimate of a global reference, and every machine's estimate drifts differently. Three concrete failure modes, all real:

The consequence: a timestamp tells you roughly when an event happened, but comparing timestamps from different machines does not reliably tell you which happened first. Yet order is exactly what we need. So we separate two ideas that wall-clock time conflates: physical time (how long ago, for humans and TTLs) and causality (what could have influenced what). Ordering correctness comes from capturing causality — logical time — not from reading a better clock.

Two clocks live in every machine: wall-clock vs monotonic

Before leaving the single machine, internalize a rule that trips up even senior engineers: never measure elapsed time with the wall clock. Operating systems expose two clocks:

The LWW footgun, grounded in this. "Last-Write-Wins" conflict resolution keeps the write with the largest wall-clock timestamp. Under clock skew, node B's clock runs 200 ms ahead; a write on A that truly happened later carries a smaller timestamp and is silently discarded — a lost update with no error, no log, no alarm. This is the concrete reason Cassandra's LWW is dangerous under contention, and the reason systems reach for the logical clocks below. LWW is not "resolve by time"; it is "resolve by whichever machine's clock is fastest".

Lamport clocks: a total order consistent with causality

Lamport's 1978 insight: forget synchronizing physical clocks; just count. Give each process an integer counter C and follow three rules:

This guarantees the clock condition: if event a happened-before b (written a → b — same process in order, or a send and its matching receive, or transitively), then C(a) < C(b). Break ties by process id and you get a total order that never contradicts causality — enough to build a replicated state machine or a mutual-exclusion protocol.

The crucial limitation, and the classic interview trap: the implication runs one way only. C(a) < C(b) does not imply a → b. Two causally-unrelated (concurrent) events can have any counter relationship. A Lamport clock can order everything, but it cannot tell you whether the order is real causality or an arbitrary tiebreak — so it cannot detect conflicts. The diagram below traces this on three processes.

Trace it: on receive of m1, P2 sets C = max(0, 2) + 1 = 3. Event e on P3 gets L=1 — the same Lamport value as a, and less than b's L=2 — even though e is causally unrelated to both. Lamport happily orders e before b, but that "order" is fiction. To detect that they are concurrent you need the vector.

Vector clocks: detecting concurrency, not just ordering it

A vector clock replaces the single counter with a vector of length N (one entry per process), so it records what each process knew, not just a scalar. Rules:

Now comparison is component-wise. V(a) ≤ V(b) iff every component of a is the corresponding component of b. Then:

In the diagram, b = [2,0,0] and e = [0,0,1]: b is bigger in position 1, e is bigger in position 3 — neither dominates, so they are provably concurrent. That is the capability Lamport lacks. This is why Amazon Dynamo and Riak attach vector clocks to each object: on read they can tell a clean overwrite (one version dominates) from a true conflict (concurrent versions), and hand concurrent siblings to the application to merge — rather than silently losing one, LWW-style.

The cost is real: metadata is O(N) per value, and N = number of writers, which grows with clients over time. Dynamo prunes the oldest vector entries past a threshold, trading a small chance of a false "no conflict" for bounded size. Version vectors (per-replica rather than per-client) keep N small when only replicas mutate. The vector-size problem is the standing objection to vector clocks in the large.

Hybrid Logical Clocks (HLC): logical causality that also tracks the wall

Vector clocks are heavy and their values are meaningless as timestamps. Lamport counters are light but tell you nothing about when. HLC (Kulkarni et al., 2014) fuses both into a single compact value (pt, l): a physical-time part pt and a small logical counter l. On each event it takes max of the local physical clock and the incoming HLC's physical part; if they tie it bumps the logical counter l; otherwise l resets. The result has three properties at once:

It fits in ~64 bits, needs no special hardware, and gives a causal, near-real timestamp. CockroachDB and MongoDB use HLC to order transactions and events across a cluster. HLC is the pragmatic default when you want causal ordering plus meaningful timestamps but cannot deploy atomic clocks.

Spanner TrueTime: external consistency by waiting out the uncertainty

Everything above gives ordering relative to observed messages. Spanner wants something stronger — external consistency (a.k.a. linearizability across the entire database): if transaction T1 commits before T2 starts in real time, then T1's commit timestamp < T2's, globally, for any keys, with no per-key leader coordinating them. You cannot get that from logical clocks alone, and you cannot get it from ordinary wall clocks (they lie). Spanner's move is to make the clock honest about its own error.

TrueTime is an API backed by GPS receivers and atomic clocks in every datacenter. Instead of returning a single instant, TT.now() returns an interval [earliest, latest] and guarantees the true current time lies somewhere inside it. The width is (typically a few milliseconds); ε is the clock uncertainty, and TrueTime knows it because it measures drift against the reference hardware. The clock no longer claims to know the time — it claims a bound on how wrong it might be.

The commit-wait trick, precisely: to commit a read-write transaction, Spanner picks a commit timestamp s = TT.now().latest (the newest instant the true time could possibly be), then does not release locks or acknowledge the client until TT.now().earliest > s — a deliberate wait of ≈ 2ε in expectation, not ε: s = TT.now().latest already sits ~ε ahead of true time at pick, and the release test TT.now().earliest > s demands true time get ~ε past s — two ε-sized gaps, one wait. The Spanner paper states it plainly: "the expected wait is at least 2·ε̄" (§4.1.2), with ε̄ ≈ 4 ms in the published deployment ⇒ ≈ 8 ms of commit latency. Why this works: after the wait, the earliest possible current time is already past s, so s is guaranteed to be in the real past by the time anyone can observe the commit. Any transaction that starts after this one's client reply will read a fresh TT.now() whose value exceeds s — so its timestamp is strictly larger. Timestamp order can never contradict real-time order. That is external consistency, purchased with a few milliseconds of latency per commit instead of a global coordinator. Smaller ε (better clocks) directly means shorter waits — which is why Google invests in the GPS+atomic hardware. The uncertainty didn't disappear; Spanner paid it off in wall-clock latency.

Selection & trade-offs: which clock, and when a logical clock is enough

The governing question is what kind of order you need and what you'll pay for it (metadata size, special hardware, commit latency). A logical clock is enough whenever ordering only needs to respect observed causality — events connected by messages you actually sent. You need a synchronized physical clock only when you must order events that never communicated, against real (external) time — e.g. "any read after this commit, anywhere, must see it."

ApproachWhat it buysWhat it costsReach for it when
No clock — consensus log order (Raft/Paxos)A single agreed total order for one group; the strongest, simplest correctnessA leader / quorum round-trip per op; order exists only within the one replicated logYou already funnel writes through one consensus group (config store, single-shard KV).
Lamport clockCheap (one int) total order consistent with causalityCannot distinguish causal from concurrent ⇒ cannot detect conflictsYou need a deterministic tiebreak / state-machine order and conflicts are impossible or handled elsewhere.
Vector clockDetects concurrency ⇒ real conflict detectionO(N) metadata per value; grows with writers; needs pruningMulti-master / AP stores that must surface conflicts to merge (Dynamo, Riak, CRDT causality).
Hybrid Logical ClockCausal order and a monotonic, meaningful, wall-close timestamp; ~64 bitsDivergence bounded by (but dependent on) clock skew; not externally consistent by itselfCluster-wide event/txn ordering with human-usable timestamps, no special hardware (CockroachDB, MongoDB).
TrueTime + commit-waitExternal consistency / global linearizability with no per-key leaderGPS+atomic clock hardware; commit latency ≈ 2ε (≈8 ms in the 2012 paper) on every writeYou need strict-serializable, real-time-correct ordering across an entire multi-shard database (Spanner).

Read the table as a ladder of ambition: order within one group (consensus) → order consistent with causality cheaply (Lamport) → detect concurrency (vector) → add meaningful physical time (HLC) → order against real time globally (TrueTime). You climb only as far as the guarantee your use case actually demands, because each rung adds cost.

Pitfalls

Takeaways


Re-authored for this guide; space-time and TrueTime diagrams hand-authored as SVG. Sources: Lamport, "Time, Clocks, and the Ordering of Events in a Distributed System" (CACM 1978); Fidge & Mattern (vector clocks, 1988); Kulkarni et al., "Logical Physical Clocks" / HLC (2014); Corbett et al., "Spanner: Google's Globally-Distributed Database" (OSDI 2012) for TrueTime and commit-wait; Kleppmann, DDIA ch. 8–9. See also: The Consistency Spectrum, CAP/PACELC, Quorum, Replication Lag & Failover. On-ramp: Time, Clocks & Ordering — Why You Can't Trust the Wall Clock (the LWW failure trace and the which-clock-for-which-problem decision table).

🤖 Don't fully get this? Learn it with Claude

Stuck on Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime** (System Design) and want to truly understand it. Explain Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Time, Clocks & Ordering — Lamport, Vector Clocks, Hybrid Logical Clocks & TrueTime** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes