# Physical Clocks and Why They Lie — Distributed Systems & Consensus (Raft / Paxos)

Source: https://www.skillbyai.com/en/distributed-consensus/dc-physical-clocks

> Explain clock skew, drift and NTP adjustments, and avoid ordering events by wall-clock timestamps.

## Each node has its own idea of 'now'

Every machine has a quartz clock that **drifts**: it runs slightly fast or slow, so two machines slowly disagree. **NTP** periodically corrects this, but only to within some milliseconds over a typical network, and a correction can make the **time-of-day clock jump backwards**. The gap between two clocks at one instant is called **skew**. Operating systems therefore offer two clocks: a **wall clock** (time of day, can jump) and a **monotonic clock** (only moves forward, meaningless across machines). Use the monotonic clock to measure durations such as timeouts on one node. Never use wall-clock timestamps from different nodes to decide which of two events happened first, because skew can be larger than the gap between the events. Systems that do rely on time, like Google Spanner with TrueTime, expose an explicit uncertainty interval and wait it out.

## From wall clocks to logical clocks

Physical clocks drift apart, Lamport clocks give a consistent total order, and vector clocks additionally detect concurrency.

![Three stages: drifting physical clocks, Lamport logical clocks, and vector clocks.](assets/figures/distributed-consensus/section-2-map.svg) — Figure 2.1: physical clocks (skew) -> Lamport clocks (order) -> vector clocks (concurrency)

## Last-writer-wins with a skewed clock loses data

Two replicas tag writes with their own wall clock and keep the highest timestamp. Replica B is 50 ms behind, so the newer write looks older and is silently discarded.

```python
# Two replicas use wall-clock timestamps for last-writer-wins (LWW).
# Replica B's clock runs 50 ms behind replica A's.
writes = [
    {"value": "price=100", "replica": "A", "ts": 1_000.000},  # happens first
    {"value": "price=120", "replica": "B", "ts": 1_000.030 - 0.050},  # 30 ms later, skewed clock
]
winner = max(writes, key=lambda w: w["ts"])
print("real order : price=100 then price=120")
print("LWW keeps  :", winner["value"])
```

Output:

```
real order : price=100 then price=120
LWW keeps  : price=100
```

## Monotonic for durations

In Python use `time.monotonic()`, in Go `time.Since` (Go's `time.Time` carries a monotonic reading), and in Java `System.nanoTime()` for elapsed time. Using wall-clock time for an election timeout can fire it instantly or never after an NTP step.

**Quiz:** Why is last-writer-wins by wall-clock timestamp risky across replicas?

- [ ] Timestamps take too much storage
- [x] Clock skew can make a later write carry a smaller timestamp, so it is discarded
- [ ] Wall clocks cannot represent milliseconds
- [ ] It requires a consensus round for every read

*Answer:* Clock skew can make a later write carry a smaller timestamp, so it is discarded. If skew exceeds the real gap between two writes, the order by timestamp differs from the real order and the newer value is lost silently.
