System Design Cases
Vector Clocks
Vector Clocks concept page: per-replica vector counter that exactly distinguishes causal vs concurrent events. 3-replica Dynamo-style cluster + 2 clients. 4 scenarios: causal chain detection, concurrent writes returning siblings, VC vs Lamport comparison showing concurrency info loss, sibling explosion anti-pattern.
Vector clocks: represent causality, not value resolution
A vector clock stores one logical counter per participant. A local event increments the local component; a send carries the vector; a receive takes componentwise maximum and then increments the receiver component. Componentwise dominance captures happens-before for the represented participant set, while incomparable vectors identify concurrent histories.
The vector is causal context, not the application value. Taking componentwise maximum merges knowledge but cannot decide how concurrent carts, balances, or document edits should combine. Payload resolution and invariant preservation remain application decisions.
Prerequisites and model
- Participants have stable identities for the lifetime represented by their vector components.
- Receive processing merges before incrementing the receiver component.
- Retries preserve operation identity because delivery and business-effect deduplication are separate.
Correctness claims and invariants
- VC-C1.
V <= Wiff every component of V is at most W; strict dominance represents causal ancestry. - VC-C2. Incomparable vectors are concurrent; a last-writer conclusion is unjustified without another policy.
- VC-C3. Receive takes componentwise max of local and remote vectors, then increments the receiver component.
- VC-C4. Max is an idempotent causal-context merge, not an automatic merge of payload values.
- VC-C5. Exact vectors grow with identities; bounding or pruning metadata can collapse distinctions and requires a defined protocol.
- VC-C6. A restart needs durable counter state or a fresh incarnation; reused low counters are unsafe.
- VC-C7. Duplicate causal metadata does not suppress duplicate side effects; operation identity remains necessary.
What the scenarios prove
- Local component tick (
local-tick): Only the executing replica component advances for a local event.
- Send and receive merge (
send-receive): The receiver takes max and then increments itself.
- Componentwise dominance (
component-compare): All components participate in ancestry comparison.
- Concurrent siblings (
concurrent-writes): Disconnected replicas advance different components and become incomparable.
- Payload resolution policy (
sibling-resolution): Causal context merges separately from application payload semantics.
- Duplicate delivery (
duplicate-delivery): Idempotent vector merge does not make the business effect idempotent.
- Pruning requires stability (
membership-pruning): Deleting a component while old history can return loses causal distinctions.
- Restart identity safety (
restart-incarnation): A low restored counter needs recovery or a fresh incarnation.
Failure, concurrency, and retry traps
- Never compare vector sums or lexicographic order as causality.
- Silently choosing one payload while merging vectors loses a concurrent update.
- Pruning an offline component without causal stability can make old messages appear fresh.
- Restoring a replica under the same identity with a lower counter violates monotonic history.
Boundaries and non-guarantees
- Vector clocks do not provide consensus, real-time ordering, or cross-key transactions.
- Metadata cost grows with identities unless a carefully specified compressed representation is used.
- Conflict detection is distinct from conflict resolution and application invariants.