Articles

What Are Vector Clocks? Ordering Distributed Events

A vector clock is a per-node counter array that lets distributed systems tell whether one event happened before another, without a shared clock.

Chisato Chisato · · 4 min read
Abstract blue network mesh of connected nodes

A vector clock is a small array of counters, one per node in a distributed system, that lets nodes determine whether one event causally happened before another — without relying on synchronized wall-clock time, which is unreliable across machines. Each node keeps its own copy of the vector, increments its own slot on every local event, and merges in the highest values it’s seen from other nodes whenever messages arrive.

The problem vector clocks solve shows up the moment you have more than one machine: if node A writes a value at 10:00:01.200 and node B writes a conflicting value at 10:00:01.150, which one happened “first”? Physical clocks on different machines drift, and network delays mean a timestamp doesn’t reliably reflect the order events actually occurred in from the system’s point of view. Vector clocks sidestep the question of physical time entirely and answer a different, more useful one: which events could have influenced which.

How the counters work

Every node maintains a vector with one entry per node in the system — [A: 0, B: 0, C: 0] to start. The rules are simple:

  1. On a local event, a node increments its own entry in the vector.
  2. When sending a message, it attaches its current vector.
  3. When receiving a message, it merges the received vector into its own by taking the element-wise maximum, then increments its own entry.
Node A: [1,0,0] → does work → [2,0,0] → sends message to B

Node B: [0,0,0] → receives A's [2,0,0]
       → merges: [max(0,2), max(0,0), max(0,0)] = [2,0,0]
       → increments own slot: [2,1,0]

That merged, incremented vector on node B now encodes something physical clocks can’t express directly: it captures every event, from any node, that causally preceded this one.

Comparing two vectors

Given two vectors, you can determine their relationship by comparing them entry by entry:

  • A happened before B if every entry in A’s vector is ≤ the corresponding entry in B’s vector, and at least one is strictly less.
  • B happened before A — the same check, reversed.
  • Concurrent — neither vector is entrywise ≤ the other. Neither event could have caused the other; they happened independently, likely on different nodes that hadn’t yet communicated.

That third case — concurrent, unordered events — is the one physical timestamps hide and vector clocks expose honestly. Two updates to the same record from two different nodes, made before either node heard about the other’s write, are genuinely concurrent: there’s no true “first” one, only two updates that need to be reconciled.

Why this matters for conflict resolution

In a system with eventual consistency, the same key can be written on different nodes before those writes propagate to each other. When the writes eventually meet, the system needs to know: was one write a deliberate update to the other (should it simply win), or were they truly concurrent (does something need to reconcile them)? A vector clock comparison answers that directly, which is why it’s a common building block underneath conflict resolution in leaderless, multi-writer systems — sometimes paired with a CRDT merge function that defines exactly how to combine two concurrent updates into one.

Contrast this with systems built around Raft or another single-leader consensus protocol: because writes go through one elected leader and are applied in one global order, there’s no ambiguity to resolve — every node agrees on a single sequence of events, and vector clocks aren’t needed. Vector clocks earn their keep specifically in leaderless systems, where concurrent writes are allowed to happen in the first place, an approach also reflected in how quorum-based systems handle reads and writes without a single coordinator.

The cost: vector size

The obvious drawback is that a vector clock’s size grows with the number of nodes that can generate events — a system with thousands of clients, rather than a small, fixed set of server nodes, would need thousands of counters attached to every event, which is impractical. Real systems address this a few ways: restricting vector clocks to a small, stable set of server-side replicas rather than every client; pruning entries for nodes that haven’t been seen in a long time; or using a related but more compact structure like dotted version vectors, which track causality per-write rather than per-node to avoid vectors growing unboundedly as replicas churn.

Vector clocks vs Lamport timestamps

A simpler, single-number alternative — a Lamport timestamp — also orders events using logical counters instead of wall-clock time, but it only produces a total order: given any two timestamps, one is always considered to come before the other, even if they were actually concurrent. That’s cheaper to store and compare, but it can’t tell you the thing vector clocks can: whether two events were genuinely independent or whether one causally depended on the other. Systems that only need “did this happen before that, for ordering purposes” can use Lamport timestamps; systems that need to detect true write conflicts need the extra information a vector clock carries.

The takeaway

Vector clocks track causality, not time — a per-node counter array that grows and merges as events and messages propagate, letting any node determine whether one event happened before another or whether the two were concurrent. That distinction is what makes reliable conflict detection possible in leaderless, multi-writer distributed systems, where relying on physical timestamps to order events would be both inaccurate and, in the case of genuinely concurrent writes, fundamentally the wrong question to ask.

The Lycoris Team The Lycoris Team · · 4 min read

Quorum Consensus Explained: N, W, and R

Quorum consensus lets distributed databases tune consistency and availability by requiring reads and writes to touch overlapping subsets of replicas.

#Databases #Distributed Systems #Cloud
Chisato Chisato · · 5 min read

Synchronous vs Asynchronous Database Replication

Synchronous replication waits for a replica to confirm a write before committing; asynchronous doesn't. The choice trades latency against durability.

#Databases #Distributed Systems #Cloud
Chisato Chisato · · 5 min read

Raft vs Paxos: Consensus Algorithms Compared

Raft and Paxos both let a distributed cluster agree on a value despite failures — Raft trades some flexibility for a design built to be understood.

#Distributed Systems #Computer Science #Databases