Clocks, ordering and why timestamps lie
Two machines never agree on the time, so never let time decide who wins.
What problem does logical clocks solve?
Every machine has a clock, and no two of them agree. They drift apart by milliseconds normally, and by much more when something goes wrong. NTP usually corrects small errors gradually, but it fixes a large one by stepping the clock, so a clock can even move backwards.
This matters because people constantly use timestamps to decide things: which write is newer, which event happened first, whether a lease expired. Each of those decisions is wrong some of the time, and nothing reports it.
What logical clocks costs you
Every concept in here states a cost. A technique with no price is a technique you have not understood yet — and naming the cost out loud is most of what separates a senior answer from a junior one.
When to reach for logical clocks, and when not to
Use it when
- Deciding which of two concurrent writes wins.
- Ordering events that arrive from different machines.
- Anything with a lease, a lock expiry or a token lifetime.
- Debugging across services, where you are lining up logs from several machines.
Do not, when
- Ordering events inside a single process or a single partition. There the sequence is already unambiguous, and a counter is enough.
- Displaying a time to a human. There a wall clock is right, because being 50 ms off does not matter.
How logical clocks actually works
First, the size of the problem. A well-run fleet with NTP keeps clocks within a few milliseconds of each other most of the time. A badly configured or briefly disconnected machine can be seconds out. And when NTP steps the clock to correct a large error, the same machine can read 12:00:00.100 and then, a moment later, 12:00:00.050. Any code that assumes time only moves forward has a bug it will hit rarely and struggle to reproduce.
So: last-write-wins is a decision to lose data, not a conflict resolution strategy. It is legitimate when the value is disposable (a presence status, a cached counter), and you should say that when you choose it. It is not legitimate for anything a user typed. If two people edit a document and one edit vanishes because a server's clock was 80 ms behind, you have not resolved a conflict. You have hidden one.
Logical clocks fix ordering without needing real time. A Lamport clock is a counter each machine keeps. Bump it on every event and send it with every message. When a message arrives, set your counter to one more than the larger of yours and the received value. That guarantees that if A caused B, then A has a lower number than B. It cannot tell you the reverse. A lower number does not prove causation, so you cannot use it to detect that two writes were concurrent.
Version vectors can. Each writer keeps its own counter, and the value carried around is the set of all of them. Comparing two versions gives you three answers, not two: this one is newer, that one is newer, or neither: they are concurrent and in conflict. That third answer is the useful one, because it hands the conflict to something that can resolve it: application logic, a merge rule, or the user. The cost is that the vector grows with the number of writers, so you need a way to prune retired ones.
Hybrid logical clocks are the practical compromise used by several distributed databases, CockroachDB among them. They combine a physical timestamp with a logical counter, so the value stays close to real time and means something when you read it, while still guaranteeing correct causal order even when the physical clocks disagree. If someone asks how you would order events across regions, this is the answer to name.
The other answer is to stop needing global order. Most systems do not need to order everything, only the things that touch each other. Ordering per key, per conversation, per account is usually enough, and it is much cheaper: route all writes for one key through one place, and the sequence is unambiguous with no clocks involved at all. Partitioning by key already gives you that. Reach for that before reaching for vector clocks.
Two practical rules. Never compare timestamps from different machines to decide a winner. And never trust a client-supplied timestamp for anything that matters, because that clock is on a phone whose owner can set it to any value they like.
- Last-write-wins on user content, described as if it resolved the conflict rather than discarded one side.
- Assuming time only moves forward. NTP can step clocks backwards.
- Trusting a timestamp sent by a client.
- Reaching for vector clocks when partitioning by key would have removed the problem entirely.
The logical clocks follow-up an interviewer will ask
"You store a last-updated timestamp and use it to resolve conflicts. What goes wrong?"
Data disappears with no error, and nobody can reproduce it. The concrete failure: two servers accept a write to the same key, one server's clock is 80 milliseconds behind, and the write that happened second carries the earlier timestamp. Last-write-wins keeps the older value and drops the newer one, so a user watches their edit apply and then revert on refresh. There is no error, no log line, nothing to alert on. It is worse in a multi-leader or multi-region setup, where the two writes are naturally on different machines. What I would do instead depends on the data. If the value is disposable, like a presence indicator, last-write-wins is fine and I would say out loud that I am choosing to lose the odd update. If it is user content, I want to detect the conflict rather than pick a winner, so I would carry a version: a version vector, or a version number with a compare-and-set write so the loser is told to retry rather than silently overwritten. Best of all, if the shape allows it, I remove the conflict: route all writes for that key through one partition, so there is a single order and no clock is involved.
Your turn
Why is "order these events by their timestamp" unreliable across machines, and what is the cheapest way to avoid needing it?
Learn it from the source
This page gets you interview-ready. These take you to where the idea is actually specified or measured — read them when you want the real depth.
- Time, Clocks, and the Ordering of Events ↗Lamport's 1978 paper. The origin of happens-before and logical clocks.
- CockroachDB — Architecture Overview ↗A production system built around clock uncertainty, and what it costs.