Skip to main content
Articles/System Design/clock-skew-and-causality-violations
Scenario Article

Clock Skew and Causality Violations: Why Distributed Clocks Lie

Why Two Machines Can Never Perfectly Agree on the Time

Abstract Algorithms•May 3, 2026
💡 Executive Summary

Physical clocks on distributed machines cannot be perfectly synchronized.

🎯 System Scenario & Requirements

System Goal

Physical clocks on distributed machines cannot be perfectly synchronized.

Actors & Components

  • Application or API tier
  • Core service under design
  • Operator or SRE observer

Functional Requirements

  • TLDR: Physical clocks on distributed machines cannot be perfectly synchronized.
  • NTP keeps them within tens to hundreds of milliseconds in normal conditions — but under load, across datacenters, or after a VM pause, the drift can reach seconds.
  • When systems use wall-clock timestamps to resolve write conflicts (Last-Write-Wins), that drift causes the correct write to lose to a stale one, silently.

Constraints & Assumptions

⚡ Execution Stages & Decision Trace

1

Stage 1 — The Basics: Clock Synchronization and Its Limits

Action / Decision:

A clock skew is the difference between the wall-clock time on two different machines at the same instant.

Component Behavior:

Even machines running NTP on the same local network diverge by 1–10 milliseconds between synchronization events.

Observable Output: Across datacenters or after a VM live-migration pause, that drift can reach seconds.
Read Full Stage in Deep Dive ↓
📖

Deep Dive

Detailed Architectural Analysis

Scenario context

Physical clocks on distributed machines cannot be perfectly synchronized. NTP keeps them within tens to hundreds of milliseconds in normal conditions — but under load, across datacenters, or after a VM pause, the drift can reach seconds. When systems use wall-clock timestamps to resolve write conflicts (Last-Write-Wins), that drift causes the correct write to lose to a stale one, silently. Causality violations are…

This walkthrough focuses on Why Two Machines Can Never Perfectly Agree on the Time.

Before making a design choice, clarify:

  • A physical clock is a counter that increments based on the oscillation frequency of a quartz crystal (in most servers) or an atomic resonator (in GPS receivers and atomic clocks).
  • Quartz crystals drift — typically by 1 to 100 parts per million — meaning a server's clock can gain or lose between 86 milliseconds and 8.6 seconds per day even without any external disturbance.
  • NTP (Network Time Protocol) corrects this by synchronizing server clocks against a hierarchy of reference clocks.

Concepts in play: consistency-replication, transaction-isolation-distributed-acid, design-patterns-gof, database-isolation-levels-anomalies

Stage 1 — The Basics: Clock Synchronization and Its Limits

  • A clock skew is the difference between the wall-clock time on two different machines at the same instant.
  • Even machines running NTP on the same local network diverge by 1–10 milliseconds between synchronization events.
  • Across datacenters or after a VM live-migration pause, that drift can reach seconds.
  • Why it matters for distributed systems: - Any operation that uses a timestamp to determine event order will get that order wrong when clocks disagree.

Observable outcome: Why it matters for distributed systems: - Any operation that uses a timestamp to determine event order will get that order wrong when clocks disagree.

Stage 2 — How Clock Skew Breaks Last-Write-Wins Conflict Resolution

  • Last-Write-Wins is the simplest conflict resolution strategy: when two replicas hold different values for the same key, the value with the higher timestamp wins.
  • The losing value is discarded.
  • In a system with perfectly synchronized clocks, this is a reasonable heuristic.
  • In a system with clock skew, it silently corrupts data.

Observable outcome: In a system with clock skew, it silently corrupts data.

Stage 3 — Deep Dive: From Lamport Clocks to Vector Clocks

  • Internals: Why Causality Breaks Without Synchronized Clocks Causality is the relationship between events where one event causes or enables another.
  • If user A posts a message and user B replies to it, A's post causally precedes B's reply.
  • A system that delivers B's reply before A's post to some observer has violated causality — the observer sees an answer to a question that hasn't been asked yet.
  • This violation can happen even with perfectly synchronized clocks, purely from asynchronous network delivery.

Observable outcome: This violation can happen even with perfectly synchronized clocks, purely from asynchronous network delivery.

Stage 4 — Visualizing Causality Violations and How Vector Clocks Detect Them

  • The sequence diagram below shows the classic causality violation: B's reply to A's post arrives at C before A's post does.
  • The vector clock attached to each message lets C detect that it is missing a causal predecessor before displaying any content.
  • The flowchart below shows how a distributed system should process incoming events using vector clocks to enforce causal delivery:
sequenceDiagram
    participant A as "Node A (poster)"
    participant B as "Node B (replier)"
    participant C as "Node C (observer)"

    A->>B: Post "Hello?" with vector [A:1, B:0, C:0]
    B->>B: Reply "Yes, hi!" with vector [A:1, B:1, C:0]
    B->>C: Deliver reply first (network path is faster)
    Note over C: C sees [A:1, B:1, C:0] but has not seen A:1
    C->>C: Detect missing predecessor — buffer the reply
    A->>C: Deliver original post (delayed path)
    Note over C: C now has A:1 — causal predecessor satisfied
    C->>C: Display post first, then reply in causal order
flowchart TD
    A["Message arrives with vector clock W"] --> B{"Is my local V causally ready\nfor W?"}
    B -->|"Yes — all W predecessors already seen"| C["Deliver message to application"]
    B -->|"No — missing causal predecessor"| D["Buffer message in causal queue"]
    D --> E["Wait for missing predecessor to arrive"]
    E --> F["Missing predecessor arrives"]
    F --> G["Deliver buffered messages in causal order"]
    C --> H["Update local vector clock\nV[j] = max(V[j], W[j]) then V[i]++"]
    G --> H

Observable outcome: The flowchart below shows how a distributed system should process incoming events using vector clocks to enforce causal delivery:

Stage 5 — Real-World Cases: Cassandra, Spanner, and the Delete-Before-Write Anomaly

  • The Cassandra Delete-Before-Write Anomaly Cassandra's LWW conflict resolution uses the timestamp embedded in each write.
  • A particularly dangerous manifestation occurs with the delete-before-write pattern: 1.
  • Client writes user.email = "a@example.com" with timestamp T=100.
  • Client deletes user.email (tombstone) with timestamp T=101.

Observable outcome: Client deletes user.email (tombstone) with timestamp T=101.

Stage 6 — Choosing the Right Clock Mechanism

Observable outcome: You can explain how “Choosing the Right Clock Mechanism” changes the architecture or implementation path.

End-to-end outcome

After working through the stages, you should be able to explain:

    • Physical clocks on distributed machines drift apart at rates of 1–100 ppm; NTP corrects this imprecisely, leaving residual errors of 10 ms to seconds depending on conditions.
    • Last-Write-Wins conflict resolution using wall-clock timestamps silently discards the correct write when any node's clock is drifted — the most-recent write in physical time loses to an earlier write with a higher tim…

Alternatives considered

The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.

Failure and degraded modes

Trade-offs Across Clock Mechanisms

  • Detection: Trade-offs Across Clock Mechanisms
  • User or operator impact: Trade-offs Across Clock Mechanisms

Share this case study

Discuss architecture trade-offs and lessons with your team.

Share:XLinkedInReddit