How do many machines agree when the network can fail?
Once data lives on more than one machine, messages get lost, clocks disagree and machines pause. This page explains what you can and cannot promise, and the tools that make machines agree: quorums, Raft, fencing tokens, logical clocks and careful retries.
TL;DR
In a distributed system you cannot trust the network, the clock or a silent machine, so you agree by majority vote and number everything.
CAP only matters during a network partition: then you either refuse requests (CP) or answer with maybe-old data (AP).
Raft picks one leader per term by majority vote; an entry is safe once a majority has it.
Locks need fencing tokens, clocks need logical counters or bounded error (TrueTime), and 2PC blocks if its coordinator dies.
"Exactly once" really means at-least-once delivery plus idempotent processing. Retry with exponential backoff and jitter.
150–300ms
Example Raft election timeout range (Raft paper)
2of 5
Failures a 5-member etcd cluster survives (etcd FAQ)
Acts like one copy; once a write finishes, everyone sees it.
Eventual consistency
Copies agree in the end, if writes stop for a while.
Consensus
Many machines agree on one value, even if some fail.
Term (epoch)
A numbered leadership period. Bigger number wins.
Majority quorum
More than half the voters, like 3 of 5.
Fencing token
A rising number given with a lock; old numbers get rejected.
Clock skew
Two machines' clocks show different times.
Logical clock
A counter that orders events without real time.
Idempotent
Doing it twice has the same effect as doing it once.
Two-phase commit (2PC)
Ask everyone "ready?", then tell everyone "commit".
Jitter
Random extra wait, so retries don't all fire together.
Why it is hard
01The eight fallacies of distributed computing
Wrong beliefs that break real systems core
Peter Deutsch wrote seven of these at Sun around 1994. James Gosling added the eighth. Each one is a thing new engineers assume, and production disproves.
1
The network is reliable
Packets drop. Use timeouts, retries and idempotent requests.
2
Latency is zero
A call across regions takes tens of ms. Batch, cache, avoid chatty calls.
3
Bandwidth is infinite
Big payloads clog links. Compress and paginate.
4
The network is secure
Encrypt in transit (TLS) and authenticate every call.
5
Topology doesn't change
Servers come and go. Use service discovery, not fixed IPs.
6
There is one administrator
Many teams and vendors own parts. Expect mixed configs.
7
Transport cost is zero
Serialising and cross-zone traffic cost CPU and money.
8
The network is homogeneous
Different hardware, OSes and protocols. Stick to standard formats.
In everyday words
Sending letters by post: some get lost, some arrive late, some arrive twice, the postman changes, and you can never tell if no reply means "no" or "letter lost".
Actually
There is no surviving Sun page with the list. The usual references are secondary: Wikipedia and Rotem-Gal-Oz's paper "Fallacies of Distributed Computing Explained". The key fact under all eight: a sender who gets no reply cannot tell whether the request was lost, the server crashed, the server is slow, or the reply was lost.
Silence is not an answer. Every design on this page exists because "no reply" has four possible meanings.
What you give up when the network splits interview favourite
CAP says: when a network partition happens (machines alive, but cut off from each other), a system must pick. Either it stays consistent (C, every read sees the latest write) and refuses some requests. Or it stays available (A, every working node answers) and may return old data.
Node 2 cannot know about x=2. It must either refuse or answer with x=1.
Common misreadings:
"Pick 2 of 3." Wrong. Partitions are not optional, so you never "pick CA" for a multi-machine system. The choice is C or A during a partition.
"AP means never consistent." Wrong. With no partition, an AP system usually is consistent within milliseconds.
CAP's C is linearizability, not the C in ACID (which means "rules like foreign keys hold").
CAP's A is strict: every non-failing node must answer. A system that answers from the majority side only is "not available" in CAP terms, yet very usable.
PACELC (Daniel Abadi, 2012) adds the everyday case: if Partition, choose A or C; Else, choose Latency or Consistency. Even with a healthy network, waiting for replicas costs time.
System (default setup)
PACELC class
Meaning
Dynamo, Cassandra, Riak
PA/EL
Stay up in a partition; prefer speed normally
VoltDB/H-Store, Megastore, BigTable, HBase
PC/EC
Always pay for consistency
MongoDB
PA/EC
As classified by Abadi in 2012
Yahoo PNUTS
PC/EL
Fast normally, stricter in a partition
In everyday words
Two bank branches lose their phone line. A customer asks branch 2 for their balance. Branch 2 can say "sorry, come back later" (consistent) or read out yesterday's number (available).
Actually
Gilbert and Lynch's 2002 proof defines C as "Atomic, or linearizable, consistency" and A as "every request received by a non-failing node in the system must result in a response". Brewer himself wrote in 2012: "The '2 of 3' formulation was always misleading because it tended to oversimplify the tensions among properties." Abadi: "The default versions of Dynamo, Cassandra, and Riak are PA/EL systems" (Abadi 2012).
Say it like this in interviews: "During a partition we choose; normally we trade latency for consistency." Then name which side your design picks and why.
A consistency model is a promise about which values a read may return. Picture each operation as a bar from when it starts to when it finishes.
Once a write has finished, a linearizable system never shows the old value again, to anyone.
Model
Promise
Works during a partition?
Example
Linearizable (strong)
Acts like one copy, in real-time order
No
etcd, ZooKeeper writes, Spanner
Sequential
One order for all, matching each client's own order, but not real time
No
Rare as a product label
Causal
If B depends on A, everyone sees A before B
Yes, if clients stick to one server
MongoDB causal sessions
Read-your-writes
You see your own writes
Yes, if clients stick to one server
Session routing to leader
Monotonic reads
Your reads never go back in time
Yes
Pin user to one replica
Eventual
Copies agree in the end
Yes
DNS, Cassandra at ONE
In everyday words
Linearizable is a single whiteboard everyone looks at. Causal is a group chat where replies never show before the message they answer. Eventual is gossip: everyone hears the news, just not at the same moment.
Actually
Jepsen defines linearizable as "Every operation appears to take place atomically, in some order, consistent with the real-time ordering of those operations". Causal: "Causally-related operations should appear in the same order on all processes". Monotonic reads: "reads cannot go backwards". And the availability rule: "All models at or stronger than read your writes can be at most sticky available" (Jepsen consistency models).
Stronger models are easier to program and cost latency and availability. Pick the weakest model your users won't notice.
Source: jepsen.io/consistency/models and its pages for linearizable, sequential, causal, read-your-writes, monotonic reads
Agreeing
04Consensus, and how Raft elects a leader
One leader per term, chosen by majority deep dive
Consensus means a group of machines agrees on one value, such as "who is leader" or "what is log entry 7", even if some crash. You need it for leader election, distributed locks and configuration. Heartbeats alone cannot do it safely.
Raft splits time into numbered terms. Each term has at most one leader. A follower that hears nothing for a random election timeout becomes a candidate, adds 1 to the term, votes for itself and asks the others.
Server 1 votes for itself, gets 2 more: 3 of 3. It needed only 2.
One vote per term. Each server votes for at most one candidate per term, first come first served. So two leaders in the same term is impossible.
Random timeouts make split votes rare: usually one server times out first and wins before others start.
Up-to-date check. A server refuses to vote for a candidate whose log is behind its own. So a new leader always has every committed entry.
Higher term wins. An old leader that sees a higher term steps down at once.
In everyday words
A class picks a monitor. Whoever notices first that there is no monitor stands up and asks for votes. Each kid votes once per round. Win more than half and you are monitor until someone stops hearing from you.
Actually
From the Raft paper: "terms act as a logical clock"; "a candidate must receive votes from a majority of the servers in the full cluster"; "Each server will vote for at most one candidate in a given term, on a first-come-first-served basis"; the example "election timeout is randomized to be between 150ms and 300ms"; and votes are given only if "the candidate's log is at least as up-to-date as the receiver's log". Election Safety: "at most one leader can be elected in a given term" (Raft paper). Google's SRE book: leader election "cannot be solved correctly by using heartbeats" alone.
Majority votes plus one vote per term make two leaders in one term impossible. That is the whole trick behind split-brain safety.
05Raft log replication, and Paxos in one paragraph
An entry is safe once a majority has it deep dive
The leader adds each client command to its log and sends it to followers (the AppendEntries message, which also works as the heartbeat). Once a majority has stored the entry, it is committed: it will never be lost. Then every server applies it to its state machine (for example, its key-value map).
Follower 2 is slow, but the leader only needs 2 of 3 copies to commit.
Cluster size
Majority needed
Failures survived
3 servers
2
1
4 servers
3
1
5 servers
3
2
7 servers
4
3
Paxos in one paragraph. Paxos (Lamport) is the older consensus algorithm, with three roles: proposers, acceptors and learners. Phase 1: a proposer picks a number n and sends "prepare n"; acceptors promise to ignore lower numbers and report any value they already accepted. Phase 2: if a majority promised, the proposer sends "accept n, v", using the highest-numbered value already accepted if there is one. A value accepted by a majority is chosen. Raft gives the same safety but was designed to be easier to understand and build; Multi-Paxos plus a stable leader looks a lot like Raft.
In everyday words
A secretary writes minutes and reads each line to the committee. Once more than half have written the line in their notebooks, it is official, even if the secretary faints right after.
Actually
Raft: "A log entry is committed once the leader that created the entry has replicated it on a majority of the servers". Log Matching: "if two logs contain an entry with the same index and term, then the logs are identical in all entries up through the given index". Paxos Made Simple: "three classes of agents: proposers, acceptors, and learners". The etcd FAQ notes that "adding a member to bring the size of cluster up to an even number doesn't buy additional fault tolerance" (etcd FAQ).
Use 3 or 5 voters. 4 costs more than 3 and survives the same single failure.
06Leader election in practice, locks and fencing tokens
Don't build consensus; borrow it interview favourite
You almost never write Raft yourself. You use a service that runs it: etcd (Raft, used by Kubernetes) or ZooKeeper (its own protocol, ZAB). Your app gets a lease or an ephemeral node, and whoever holds it is leader.
ZooKeeper recipe: each candidate creates an ephemeral, sequential node (it vanishes when the session dies, and gets a growing number). Lowest number is leader. Each other node watches only the one just below it, so a leader death wakes one node, not all.
etcd: the Go concurrency package offers locks and elections built on a lease that the client keeps alive.
But a lock alone is not safe. A client can pause (garbage collection, a slow disk) after getting the lock. Its lease expires, another client gets the lock, and then the first one wakes up and writes anyway.
The storage checks the number, not the clock. Old numbers lose.
In everyday words
A deli ticket machine. Number 33 dozed off; the counter already served 34. When 33 wakes up and shouts, the clerk says "we're past you" and ignores it.
Actually
Martin Kleppmann (2016): a fencing token is "simply a number that increases (e.g. incremented by the lock service) every time a client acquires the lock", and the storage rejects any write with a lower token than one it has already processed. ZooKeeper: "use the SEQUENCE|EPHEMERAL flags", and "To avoid the herd effect, it is sufficient to watch for the next znode down". etcd's concurrency package "implements concurrency operations on top of etcd such as distributed locks, barriers, and elections" (Kleppmann, ZooKeeper recipes, etcd concurrency).
A lock is a hint, not a guarantee. The resource you protect must check a fencing token, or a paused client will corrupt it.
Skew, NTP, Lamport, vector, hybrid clocks, TrueTime deep dive
Every machine has its own quartz clock, and they drift apart. NTP (Network Time Protocol) pulls them back toward a time server, but only to within some error. So "write A has timestamp 10:00:00.005, write B has 10:00:00.003" does not prove B happened first.
The fix is to order events by cause, not by wall time. Lamport's rule: keep a counter. Add 1 before each event. Send the counter with each message. On receive, set counter = max(mine, message) + 1.
Time runs left to right on each process. A receive always gets a bigger number than its send.
Clock
What it stores
What it can tell you
Used in
Physical (wall) clock + NTP
Real time, with error
Rough time. Not safe for ordering close events.
Logs, TTLs, last-write-wins
Lamport clock
One counter
If A caused B, then L(A) < L(B). The reverse is not true: a smaller number does not prove a cause.
Total ordering, tie-break by node id
Vector clock
One counter per node
Whether A caused B, B caused A, or they were concurrent (a conflict)
Dynamo, Riak versions
Hybrid logical clock (HLC)
Physical time + small counter
Causal order, and stays close to real time
CockroachDB, YugabyteDB
TrueTime
An interval [earliest, latest]
Real order, if you wait out the uncertainty
Google Spanner
In everyday words
Two friends' watches are a few minutes apart, so their photo timestamps can't be trusted. But a reply to a text always comes after the text. Lamport clocks keep only that "reply after text" rule.
Actually
NTP (RFC 5905): "servers and clients are precise within a few tens of milliseconds" on the Internet, and "clients on fast LANs are within a few hundred microseconds". Lamport 1978, rule IR2: "Upon receiving a message m, process Pi sets Ci greater than or equal to its present value and greater than Tm." Spanner: TT.now() returns "[earliest, latest]"; "ε is typically a sawtooth function of time, varying from about 1 to 7 ms ... ε is therefore 4 ms most of the time", backed by "GPS and atomic clocks". With commit wait, Spanner waits until TT.after(s) is true before showing a commit, so timestamps match real order. CockroachDB uses HLC and its --max-offset default is 500 ms; nodes whose clocks drift too far shut down (Spanner paper, CockroachDB docs, checked 2026-10-25).
Never decide "which write came first" by wall clock alone. Use logical counters, vector clocks for conflicts, or bounded uncertainty plus waiting.
Atomic writes across machines, at a price interview favourite
Two-phase commit (2PC) makes a transaction across several databases all-or-nothing. Phase 1: the coordinator asks each participant "prepare": write everything durably, keep locks, and vote yes or no. Phase 2: if all said yes, it sends "commit"; otherwise "abort".
After voting yes, a participant may not decide alone: the others might have aborted.
Option
How it handles cross-service writes
Cost
2PC (XA, PostgreSQL PREPARE TRANSACTION)
Atomic: all commit or all abort
Blocks when the coordinator dies; locks held; slow
2PC with a replicated coordinator
Coordinator state kept by consensus (as Spanner does with Paxos groups)
Complex; still extra round trips
Saga
A chain of local transactions; on failure run undo steps
Not isolated: others can see half-done work
Outbox + events
Write data and an event in one local transaction; publish later
Eventually consistent
In everyday words
A wedding officiant asks both people "do you?". Both say yes. Then the officiant faints before saying "you are married". Are they married? Nobody may leave until the officiant wakes up.
Actually
Gray and Lamport: "The classic Two-Phase Commit protocol blocks if the coordinator fails." PostgreSQL warns: "It is unwise to leave transactions in the prepared state for a long time", because the transaction "continues to hold whatever locks it held" (Consensus on Transaction Commit, PostgreSQL PREPARE TRANSACTION).
2PC gives atomicity and costs availability. In microservices, prefer sagas or the outbox pattern unless you truly need all-or-nothing.
You can't stop duplicates; you can make them harmless core
When a reply is lost, the client retries. The server may have done the work already. So over a network you can choose at-most-once (never retry, may lose) or at-least-once (retry, may duplicate). True exactly-once delivery is impossible in general.
What you can get is exactly-once effect: at-least-once delivery plus idempotent processing, so a duplicate changes nothing.
Pattern
Idempotency key
Client sends a unique key with "charge $10". Server stores key and result. A retry with the same key returns the saved result.
Pattern
Naturally idempotent writes
"Set balance to 90" is safe to repeat. "Subtract 10" is not.
Pattern
Dedup table
Consumers record processed message ids, in the same transaction as the work.
Pattern
Version check
"Update if version = 7". A replay sees version 8 and does nothing.
HTTP · idempotency key on a payment call
POST /payments
Idempotency-Key: 8f1c2a7e-... # same key on every retry
{"amount": 1000, "currency": "INR"}
# server: INSERT key UNIQUE; if it already exists, return the stored response
In everyday words
Pressing a lift button five times calls the lift once. Design every request to be like the lift button, not like a vending machine that drops a can each time.
Actually
Kafka's design docs: "The idempotent delivery option guarantees that resending a message will not result in duplicate entries in the log", and for read-process-write between Kafka topics "Kafka leverages transactional producer capabilities added in version 0.11.0.0 to achieve exactly once semantics". That guarantee covers Kafka-to-Kafka; writing to an outside database still needs your own idempotency or storing offsets with the data (Kafka delivery semantics; the Apache page needs JavaScript, so Confluent's copy was read).
Say "effectively once": at-least-once delivery plus idempotent handlers. Anyone promising more has a narrow scope in the small print.
A node is suspected dead when its heartbeats stop for longer than a timeout. A fixed timeout is a guess: too short gives false alarms during a GC pause, too long gives slow recovery.
The phi accrual detector learns the normal gap between heartbeats and outputs a suspicion number, phi, instead of yes/no. Higher phi means "more surely dead". You pick the threshold.
Retries must back off. If 1,000 clients all retry after exactly 1 second, they hit the recovering server together (a "thundering herd"). Exponential backoff doubles the wait each try; jitter picks a random wait up to that limit, spreading clients out.
Upper limit of the wait before each retry (base 100 ms, doubling)
Full jitter waits a random time between 0 and this limit. Computed from the formula below; a cap stops growth.
Fault types. Everything on this page assumes crash faults: nodes stop or go slow, but never lie. Byzantine faults are nodes that send wrong or malicious messages; tolerating f of them needs at least 3f + 1 nodes, which is why blockchains, not databases, pay that cost.
In everyday words
When a shop reopens after a power cut, if everyone rushes back at 10:00 sharp, the door jams. If each person waits a random few minutes, the queue flows.
Actually
Akka: "phi = -log10(1 - F(timeSinceLastHeartbeat))" and "The default threshold is 8"; Cassandra's cassandra.yaml shows # phi_convict_threshold: 8 as the default. Marc Brooker (AWS, 2015): "Of the jittered approaches, 'Equal Jitter' is the loser", and between Decorrelated and Full Jitter "is less clear. The 'Full Jitter' approach uses less work, but slightly more time." Byzantine Generals (1982): "no solution with fewer than 3m + 1 generals can cope with m traitors" (AWS backoff and jitter, Akka failure detector, Lamport et al. 1982).
Timeouts guess, phi accrual guesses better. Always cap retries, back off exponentially and add jitter, and only retry idempotent calls.
Not an option with more than one machine. Partitions happen; you choose what to do then.
Trap
Leader election with heartbeats only
A slow network makes two nodes each think the other died. Use a majority vote.
Trap
Lock without fencing
A paused holder wakes up and writes after its lease expired.
Trap
Ordering by timestamps
NTP error is tens of ms. Close writes can be ordered wrongly.
Trap
"Kafka gives exactly once"
Only Kafka-to-Kafka with transactions. Side effects elsewhere still need idempotency.
Trap
Retrying without jitter
Synchronised retries knock a recovering service down again.
Trap
Retrying non-idempotent calls
A lost reply plus a retry charges the card twice.
Trap
Four-node consensus cluster
Needs 3 votes, survives only 1 failure, same as 3 nodes.
—Interview questions
20 questions, easy to hard, with model answers practice
State the CAP theorem correctly. easy
Show answer
If the network partitions, a distributed system must choose between consistency (every read sees the latest write, in the linearizable sense) and availability (every non-failing node answers). It is not "pick 2 of 3": partitions are not optional, so the real choice is C or A during a partition. Brewer himself called the "2 of 3" framing misleading in 2012. Example: etcd refuses writes on the minority side (CP); Cassandra at ONE answers with possibly old data (AP). Follow-up: "What about when there's no partition?" That's PACELC.
What is PACELC and why does it matter more day to day? medium
Show answer
PACELC (Abadi, 2012): if Partition, choose Availability or Consistency; Else, choose Latency or Consistency. Partitions are rare, but the latency cost of waiting for replicas is paid on every request. Dynamo, Cassandra and Riak default to PA/EL: fast and available, weaker consistency. VoltDB, Megastore and HBase are PC/EC. In design interviews this is how I justify, say, reading from a local replica: I accept slightly old data to save a cross-region round trip of tens of milliseconds.
Name the fallacies of distributed computing. Which bites most? easy
Show answer
The network is reliable; latency is zero; bandwidth is infinite; the network is secure; topology doesn't change; there is one administrator; transport cost is zero; the network is homogeneous. The first bites most: a missing reply can mean the request was lost, the server crashed, it is slow, or the reply was lost. So every remote call needs a timeout, a retry policy, and an idempotent design so retries are safe.
Linearizable vs eventual consistency: explain with an example. easy
Show answer
Linearizable: the system behaves like one copy; once a write finishes, every later read by anyone returns it. Eventual: replicas may return old values for a while but converge if writes stop. Example: after I change my password, a linearizable store guarantees the old one stops working everywhere at once; an eventual store might accept it for a few hundred milliseconds on a lagging replica. Linearizable costs latency and fails on the minority side of a partition; eventual stays up and fast.
What is causal consistency and when is it enough? medium
Show answer
If operation B depends on A (B read A's result, or the same client did A then B), every node shows A before B. Unrelated writes may appear in any order. It's enough for comments and chats: a reply never appears before its question. It is the strongest model that stays available during partitions if clients stick to one server ("sticky available" in Jepsen's terms). Implemented with dependency tracking, like vector clocks or session tokens; MongoDB offers causally consistent sessions.
Why do we need consensus? Why not just heartbeats? medium
Show answer
To make several machines agree on one value, such as who is leader or what the next log entry is, even if some crash. Heartbeats only tell you that you haven't heard from someone; on a slow or split network, two nodes can each conclude the other is dead and both act as leader. Consensus adds majority voting and numbered terms, so at most one leader per term can exist. Google's SRE book: leader election "cannot be solved correctly by using heartbeats".
Walk me through a Raft leader election. medium
Show answer
A follower hears no heartbeat for its randomized election timeout (the paper's example is 150 to 300 ms). It becomes a candidate, increments the term, votes for itself and sends RequestVote. Each server votes once per term, first come first served, and only if the candidate's log is at least as up-to-date as its own. With a majority, it becomes leader and sends heartbeats. If the vote splits, the term times out and a new election starts; random timeouts make repeats rare. A leader seeing a higher term steps down.
When is a Raft log entry committed? What if the leader crashes right after? hard
Show answer
When the leader that created it has stored it on a majority of servers. If the leader then crashes, any new leader must win votes from a majority, and the up-to-date check means it overlaps with at least one server that has the entry, so it has the entry too (Leader Completeness). Entries that were only on a minority may be overwritten. A subtle rule: a leader only counts replicas for entries from its own current term; older-term entries become committed indirectly.
Why are consensus clusters 3 or 5 nodes, not 4 or 6? easy
Show answer
A majority of n is floor(n/2) + 1. Three nodes need 2 and survive 1 failure; four need 3 and still survive only 1. So the fourth node adds cost and an extra machine that can fail, with no extra fault tolerance. Five survive 2, seven survive 3. More nodes also slow writes since more acks are needed. The etcd FAQ says the same: going to an even size "doesn't buy additional fault tolerance".
Explain Paxos in 30 seconds. hard
Show answer
Roles: proposers, acceptors, learners. Phase 1: a proposer picks a unique number n and sends prepare(n); each acceptor promises to ignore anything numbered below n and returns any value it already accepted. Phase 2: with promises from a majority, the proposer sends accept(n, v), where v is the highest-numbered already-accepted value, or its own if none. When a majority accepts, v is chosen. Multi-Paxos keeps a stable leader to skip phase 1 per entry, which ends up close to Raft.
How would you implement leader election for a cron service with 3 instances? medium
Show answer
Don't write consensus; use etcd or ZooKeeper. With etcd: each instance creates a lease (say 10 s TTL) and campaigns using the concurrency election API; the winner keeps the lease alive and runs jobs. With ZooKeeper: each creates an ephemeral sequential znode; lowest number leads, others watch the next-lower node. The leader must stop work if it loses its lease, and jobs must be idempotent or fenced, because a paused old leader may still run a job once.
What is a fencing token and why is a lock with a TTL not enough? hard
Show answer
A lock with a TTL fails when the holder pauses: GC, swapping or a slow network. The lease expires, another client gets the lock, then the first wakes and writes, and both write. A fencing token is a number that grows every time the lock is granted (33, then 34). Clients send it with every write and the storage rejects any token lower than the highest it has seen. Kleppmann's 2016 post shows this exact GC-pause case. etcd's revision numbers can serve as tokens.
Why can't you order events by timestamp across servers? medium
Show answer
Clocks drift and NTP only bounds the error: RFC 5905 says "a few tens of milliseconds" over the Internet, a few hundred microseconds on a LAN. Clocks can also jump backwards after a sync. So two writes 5 ms apart on different machines can be ordered wrongly, and last-write-wins then silently drops the newer one. Fixes: Lamport clocks for causal order, vector clocks to detect concurrency, HLC to stay close to real time, or TrueTime with commit wait.
Lamport clock vs vector clock? medium
Show answer
A Lamport clock is one counter: increment per event, send it, and on receive take max plus 1. It ensures if A caused B then L(A) < L(B), giving a total order with node-id tie-breaks, but a smaller number doesn't prove causation. A vector clock keeps one counter per node; comparing two vectors tells you A before B, B before A, or concurrent. That's why Dynamo uses vector clocks: concurrent versions are real conflicts it returns to the app. Cost: size grows with the number of nodes.
How does Spanner get external consistency with TrueTime? hard
Show answer
TrueTime returns an interval [earliest, latest] with bounded uncertainty ε, kept small with GPS and atomic clocks; the paper reports about 1 to 7 ms, 4 ms most of the time. A transaction takes commit timestamp s = TT.now().latest, then waits until TT.after(s) is true before making the commit visible: "commit wait". After that wait, s is guaranteed to be in the past everywhere, so timestamp order matches real-time order. The cost is about 2ε of added latency per write, which is why small ε matters.
What is two-phase commit and what is its main problem? medium
Show answer
Phase 1: the coordinator asks all participants to prepare; each makes the change durable, holds locks and votes yes or no. Phase 2: commit if all said yes, else abort. Problem: it blocks. If the coordinator crashes after participants vote yes, they cannot decide alone, since another may have voted no, so they hold locks until it returns. Gray and Lamport: "The classic Two-Phase Commit protocol blocks if the coordinator fails." Mitigation: replicate the coordinator's decision with consensus, or avoid 2PC with sagas.
Is exactly-once delivery possible? medium
Show answer
Not as pure delivery over an unreliable network: if an ack is lost, the sender must either retry (possible duplicate) or not (possible loss). What we build is exactly-once effect: at-least-once delivery plus idempotent processing, via idempotency keys, dedup tables, or upserts. Kafka's idempotent producer and transactions give exactly-once for read-process-write between Kafka topics; once you call an external API or database, you still need your own dedup or to store offsets with the data atomically.
Design retries for a payment service calling a bank API. design
Show answer
(1) Generate an idempotency key per payment and send it on every attempt; the bank (or our own table) dedups. (2) Set a timeout per attempt, say 2 s, and an overall deadline. (3) Retry only on safe errors: timeouts, 503, connection reset; never on 400. (4) Capped exponential backoff with full jitter: sleep = random(0, min(cap, base·2^n)), max 3 to 5 attempts. (5) A circuit breaker stops retries when the bank is clearly down. (6) After a timeout, query payment status before retrying, since the charge may have succeeded.
How do you detect failed nodes? What is phi accrual? hard
Show answer
Nodes exchange heartbeats; missing them beyond a timeout marks a node suspect. Fixed timeouts are brittle: GC pauses and network jitter cause false positives. The phi accrual detector (Hayashibara et al., 2004) learns the distribution of heartbeat gaps and computes phi = -log10(probability the heartbeat is still coming). Phi grows as silence lengthens relative to normal. Akka and Cassandra default to a threshold of 8. Higher threshold: fewer false alarms, slower detection. Always pair detection with fencing, since a suspect may be alive.
Design a distributed rate limiter that stays correct during a network partition. design
Show answer
First pick a CAP side. Strict limits (paid API quotas): CP, a central counter in Redis or a consensus store; during a partition, the cut-off side fails closed or open by policy. Most rate limits are soft: AP is fine, so each region or node keeps local counters with a share of the quota and syncs periodically, accepting slight overshoot. Use token buckets, keys per user, TTLs to expire state, and idempotent increments. I'd state the overshoot bound explicitly, e.g., "at most N regions × local share".
—Cheat sheet
Numbers and facts to remember memorise
Fact
Value
Source
CAP choice
Only during a partition: C or A
Gilbert & Lynch 2002, Brewer 2012
PACELC: Dynamo, Cassandra, Riak
PA/EL
Abadi 2012
Majority of n
floor(n/2) + 1
Raft paper
Failures survived: 3 / 5 / 7 nodes
1 / 2 / 3
etcd FAQ
Raft example election timeout
150–300 ms, random
Raft paper
NTP accuracy
tens of ms (Internet), hundreds of µs (LAN)
RFC 5905
Spanner ε
1–7 ms, about 4 ms typical
Spanner paper
CockroachDB --max-offset
500 ms default
CockroachDB docs, checked 2026-10-25
Phi accrual threshold
8 default
Akka docs, cassandra.yaml
Full jitter
random(0, min(cap, base*2**n))
AWS Architecture Blog
Byzantine tolerance
3f + 1 nodes for f faulty
Lamport et al. 1982
2PC weakness
Blocks if coordinator fails
Gray & Lamport
—Sources
All checked 2026-10-25 references
What
Where
Fallacies of distributed computing (secondary; no Sun original)