System Design Concepts

No fluff — visual, concise, interview-ready

🏗️ 12 · DISTRIBUTED SYSTEMS PATTERNS & PAPERS

Distributed System Patterns

Core patterns powering every distributed system — know these cold

PatternWhatGuaranteeUsed By
WALLog changes before applyingCrash recoveryPostgres, Kafka, etcd
Segmented LogSplit log into fixed-size segmentsPrevents unbounded growthKafka log segments
High-Water MarkHighest committed offset all replicas haveConsumers can't read uncommitted dataKafka, Raft
QuorumMajority (N/2+1) agreementW+R>N guarantees consistencyCassandra, Raft, Paxos
Leader-Follower1 leader writes, followers replicateSingle source of truth for writesPostgres, Kafka, Raft
HeartbeatPeriodic "I'm alive" messagesMissing heartbeats trigger failure detectionZooKeeper, K8s probes
LeaseTime-bounded lock/permissionAuto-expires → no stale locksChubby, ZooKeeper, DynamoDB
Gossip ProtocolNodes randomly exchange stateEventually all nodes convergeCassandra, Consul, Redis Cluster
Phi AccrualAdaptive failure detectionBetter than fixed timeoutsCassandra, Akka
Split BrainPartition causes two leadersPrevented by quorumZooKeeper, etcd
Fencing TokensMonotonic tokens for stale leader preventionOld leader's writes rejectedZooKeeper, Redlock
Merkle TreesHash tree for efficient data comparisonO(log N) syncCassandra, Git, blockchain
Hinted HandoffNeighbor stores write when target is downDelivers when target recoversCassandra, DynamoDB
Read RepairOn read, fix stale replicasLazy consistency fixCassandra, DynamoDB
ChecksumHash of data to detect corruptionVerified on readHDFS, S3, Kafka, TCP

ZooKeeper

Distributed coordination — leader election, locks, config, service discovery. ZAB consensus.

Guarantees: Linearizable writes. Sequential consistency for reads. Ephemeral nodes auto-delete on session end. Watches — one-time triggers on znode changes.
Real-world: Kafka (pre-KRaft), HBase, Hadoop YARN. Alternatives: etcd (Raft, K8s), Consul (Raft, service mesh).

GFS & HDFS

Foundational distributed file systems — GFS (Google, 2003) inspired HDFS (Hadoop)

GFSHDFS
ArchitectureSingle Master + ChunkServersNameNode + DataNodes
Block Size64MB chunks128MB blocks
Replication3 replicas, rack-aware3 replicas, rack-aware
WritePipeline to ChunkServersPipeline to DataNodes
ConsistencyRelaxed (at-least-once appends)Write-once-read-many
Guarantees: Fault tolerance via replication + checksums. High throughput for sequential reads. GFS evolved into Colossus. HDFS is foundation of Hadoop ecosystem.

BigTable

Google's wide-column DB (2006) — inspired Cassandra, HBase. Sparse sorted map: (row, column:qualifier, timestamp) → value.

Guarantees: Sorted by row key. Tablets auto-split on size. Storage: memtable → SSTable → compaction. Dependencies: GFS + Chubby. Influenced: HBase, Cassandra, Cloud Bigtable.

Fault Tolerance & Reliability

Survive failures without losing functionality

Circuit Breaker

Fail-fast protection pattern — fuse for Microservices that prevents cascading failures

CLOSED ✅ Service healthy Requests pass normally Error count reset on success errorRate > threshold OPEN 🔴 Failing fast Calls short-circuited Recovery timer running wait (coolDownPeriod) HALF- OPEN 🟡 Trial period Allow limited test calls success ✓ → CLOSED fail ✗ → OPEN Config failureThreshold: 5 coolDown: 30s halfOpenMax: 3 calls successThreshold: 2
Why It Matters — Cascading Failure

❌ Without Circuit Breaker

Client Service A Service B (slow) 🐌 threads blocked ↓ 💥 Entire system collapses

✓ With Circuit Breaker

Client Service A ⚡ Circuit Breaker OPEN → fail fast (no call to B) ✅ Service C unaffected ✅ System stable
Fallback on OPEN: Return cached response, default value, or friendly error ("Try again later") — instead of 500. Real-world: Netflix Hystrix (pioneered). Resilience4j (Java). Envoy/Istio (service mesh, built-in). Polly (.NET).
PatternHowGuarantee
TimeoutsFail fast after N secondsPrevents indefinite waiting
Retries + Backoff0s→1s→2s→4s + jitterRecovers from transient failures without thundering herd
Circuit BreakerCLOSED→OPEN→HALF_OPENFast-fail when downstream broken. Self-healing.
BulkheadsIsolate thread pools per dependencyOne hanging service doesn't starve others
Health ChecksLiveness (alive?) + Readiness (can serve?)LB/K8s auto-removes unhealthy instances
Graceful DegradationServe stale cache, disable non-critical featuresPartial outage ≠ total failure
Availability: 99.9% = 8.76h downtime/yr · 99.99% = 52min · 99.999% = 5min
Formula: Downtime = (1 - availability) × 365 × 24 × 60 min
Serial:  A_total = A1 × A2  (each component multiplies)
Parallel: A_total = 1 - (1-A1)(1-A2)  (redundancy improves)
Guarantee: No SPOF — at least 2 of everything. Netflix Chaos Monkey randomly kills production instances.
More Patterns: Leader Election — Raft: candidates request votes, majority wins, leader sends heartbeats. If heartbeat missed → new election. Used by etcd, CockroachDB, Consul. Chaos Engineering — intentionally inject failures in production to find weaknesses. Chaos Monkey (Netflix), Litmus (K8s), Gremlin. Test: kill pods, add latency, partition network, fill disk. Distributed Tracing Internals — inject trace_id + span_id into every request header. Each service creates a child span. Collect via OpenTelemetry SDK → Collector → Jaeger/Datadog. Enables: latency breakdown per service, dependency mapping.

Data Redundancy & Recovery

Survive hardware failures, data corruption, and disasters without losing data

StrategyHowRPO / RTOUse Case
ReplicationSync/async copies across nodesRPO: 0 (sync) or seconds (async). RTO: seconds (auto-failover)HA databases (Postgres replicas, Cassandra ring)
Erasure CodingSplit data into fragments + parity. Reconstruct from subset.RPO: 0. RTO: minutes (rebuild)Object storage (S3 uses Reed-Solomon), HDFS
SnapshotsPoint-in-time copy of entire datasetRPO: hours (last snapshot). RTO: minutes–hoursDB backups (RDS snapshots), VM snapshots
WAL / BinlogContinuous log of all changes. Replay to recover.RPO: ~0 (continuous). RTO: minutes (replay)Postgres PITR, MySQL binlog replication
Geo-RedundancyReplicate across regions (100+ km apart)RPO: seconds (async). RTO: minutes (DNS failover)Disaster recovery — survive entire region failure
Key Terms: RPO (Recovery Point Objective) — max data loss tolerable (how far back?). RTO (Recovery Time Objective) — max downtime tolerable (how fast to recover?). 3-2-1 Rule — 3 copies, 2 different media, 1 offsite. Hot standby = instant failover. Warm = minutes. Cold = hours (cheapest).

Leader Election for Auto-Recovery

When the leader dies, the cluster must automatically elect a new one — no human intervention

AlgorithmHow It WorksUsed By
RaftNodes start as followers. On leader timeout → become candidate → request votes from majority → win = new leader → send heartbeats. Understandable by design.etcd, CockroachDB, Consul, TiKV
ZABZooKeeper Atomic Broadcast. Leader proposes, followers ACK. On failure → new leader elected from most up-to-date follower.ZooKeeper, Kafka (pre-KRaft)
KRaftKafka's built-in Raft (replaces ZooKeeper). Controller quorum elects active controller. Simpler ops.Kafka 3.3+
BullyHighest-ID node wins. Simple but not partition-tolerant. Rarely used in production.Legacy systems
Auto-Recovery Flow: Leader dies → followers detect missing heartbeat (timeout: 150-300ms) → election starts → new leader elected (majority quorum) → new leader takes over writes → clients redirected → total downtime: 1-5 seconds. No human needed. Split-brain prevention: quorum ensures only one leader (majority of N/2+1 must agree).
Real-world: etcd (K8s control plane) — Raft, 5-node cluster, leader election in ~1s. Kafka KRaft — controller quorum, no ZooKeeper dependency. Redis Sentinel — monitors master, promotes replica on failure (not consensus-based, simpler). Postgres — Patroni + etcd for automated failover.
Raft Consensus — Visual Walkthrough (3-Node Cluster)
Phase 1: Leader Election (Term 1) Node A CANDIDATE Node B FOLLOWER Node C FOLLOWER RequestVote ✓ Vote granted ✓ Vote granted Node A wins (2/3 majority) → LEADER Phase 2: Log Replication Node A LEADER Log: x=1 y=2 z=3 Node B AppendEntries Node C AppendEntries ACK ✓ ACK ✓ Majority ACK → Entry committed Phase 3: Commit & Apply to State Machine State Machine (all nodes) x = 1, y = 2, z = 3 All replicas converge to same state Client Read/Write Writes → Leader only Reads → Leader (linearizable) or Follower (stale OK) Term Numbers Monotonically increasing epoch Stale leader detected by lower term Raft Node State Machine FOLLOWER CANDIDATE LEADER election timeout wins majority discovers leader or new term discovers higher term
Raft vs Paxos Comparison
AspectRaftPaxos (Classic)
Design GoalUnderstandability — decomposed into sub-problemsCorrectness proof first, hard to implement
LeaderStrong leader required; all writes go through leaderNo inherent leader (Multi-Paxos adds one)
LogContiguous log, no gaps allowedGaps possible, out-of-order commits
Membership ChangeJoint consensus (built-in)Not specified in original paper
Implementation~2000 lines (etcd/raft)Notoriously difficult to implement correctly
LivenessGuaranteed with leader (leader liveness assumed)Can livelock with competing proposers
Performance1 RTT for committed writes (leader → followers)2 RTTs (Prepare + Accept) unless Multi-Paxos
Used Byetcd, CockroachDB, Consul, TiKV, RethinkDBChubby, Spanner, Megastore

Consensus Protocols

Agreement among distributed nodes — the hardest problem in distributed systems. FLP impossibility: no deterministic consensus in async system with even 1 crash.

Classic Paxos — 4 Phases (5-Node Cluster)
Phase 1a: PREPARE Phase 1b: PROMISE Phase 2a: ACCEPT Phase 2b: ACCEPTED Proposer A1 A2 A3 A4 A5 Prepare(n=1) "Will you promise not to accept proposals < n?" Promise(n=1) ✓ Promise(n=1) ✓ Promise(n=1) ✓ ✗ (already promised n=2) Promise(n=1) ✓ 4/5 promised → quorum met Accept(n=1, v="X") "Please accept value X for proposal n=1" Accepted(n=1, v="X") ✓ Accepted(n=1, v="X") ✓ Accepted(n=1, v="X") ✓ Accepted(n=1, v="X") ✓ 4/5 accepted → VALUE CHOSEN ✓ Paxos Safety Guarantee Once a value is chosen (majority accepted), no other value can ever be chosen for that slot. Key insight: Proposer must adopt any previously accepted value during Prepare phase → prevents conflicts.
Multi-Paxos Optimization: Classic Paxos requires 2 RTTs per decision (Prepare + Accept). Multi-Paxos elects a stable leader who skips Phase 1 for subsequent proposals — reducing to 1 RTT (just Accept). Leader holds a "lease" on proposal numbers. If leader fails, new leader runs full Paxos once, then resumes fast path. Used by: Google Spanner, Chubby.
Raft Log Replication Detail (AppendEntries RPC): Leader maintains nextIndex[] and matchIndex[] per follower. On client write: (1) Leader appends to local log. (2) Sends AppendEntries(term, leaderId, prevLogIndex, prevLogTerm, entries[], leaderCommit) to all followers. (3) Follower checks prevLogIndex/prevLogTerm match — if not, rejects (leader decrements nextIndex and retries). (4) On majority ACK → leader advances commitIndex. (5) Next heartbeat carries updated leaderCommit → followers apply to state machine.
Consensus Protocol Comparison
ProtocolLeader Required?RTTs (steady state)Log OrderingMembership ChangeUsed By
RaftYes (strong leader)1 RTTStrict sequential, no gapsJoint consensus (built-in)etcd, CockroachDB, Consul
Multi-PaxosYes (elected proposer)1 RTT (after leader elected)Gaps possible, out-of-orderSeparate protocol neededSpanner, Chubby, Megastore
ZABYes (primary)1 RTTFIFO + causal orderingReconfiguration protocolZooKeeper
Viewstamped ReplicationYes (primary)1 RTTSequential within viewView change protocolAcademic, influenced Raft
EPaxosNo (leaderless)1 RTT (fast path, no conflicts)Dependency graphComplexResearch, some Google systems
Key Insight: All practical consensus protocols converge on a stable leader pattern for performance. The difference is in how they handle leader failure, log gaps, and membership changes. Raft wins on understandability; Multi-Paxos wins on flexibility; ZAB wins on ordering guarantees.

Clocks & Time in Distributed Systems

No global clock exists — ordering events across machines is fundamentally hard. Three approaches: physical, logical, hybrid.

Physical vs Logical vs Hybrid Logical Clocks
Physical Clocks (Wall-clock time) Node A 10:00:00.000 Node B 10:00:00.150 ⚠️ 150ms skew! Problems: • NTP accuracy: 1-100ms (LAN/WAN) • Clock drift: ~200 ppm (17s/day) • Leap seconds, NTP jumps Google TrueTime GPS + atomic clocks → ε < 7ms Returns interval [earliest, latest] Used by: Spanner (commit-wait) Wait ε before reporting commit → external consistency guaranteed Logical Clocks (Causality tracking) Lamport Timestamps Rules: (1) Before event: C++ (2) On send: attach C (3) On receive: C = max(C, msg.C) + 1 ⚠️ Cannot detect concurrency a→b implies L(a)<L(b), but L(a)<L(b) ≠ a→b Vector Clocks Each node maintains [N1, N2, N3] On local event: increment own slot On receive: element-wise max + inc ✓ Detects causality AND concurrency a→b: V(a) < V(b) (all slots ≤, at least one <) concurrent: neither V(a)≤V(b) nor V(b)≤V(a) ⚠️ O(N) space per event (N = nodes) Used by: DynamoDB, Riak, Voldemort Hybrid Logical Clocks (Best of both worlds) HLC Timestamp Structure: physical logical node_id (48 bits) + (16 bits) + (16 bits) Properties: ✓ Captures causality (like logical) ✓ Close to wall-clock (like physical) ✓ Bounded drift from physical time ✓ O(1) space (not O(N) like VC) Used By: CockroachDB, YugabyteDB, MongoDB Enables MVCC + snapshot isolation
Lamport Timestamps — Example
Node A:  event(1) → send(2) ─────────────────→ event(5)
Node B:  event(1) → event(2) → recv(3) → event(4) → send(5)
Node C:  event(1) ──────────────────────→ recv(6) → event(7)

Rules: On local event: C = C + 1
       On send: attach timestamp C
       On receive: C = max(local_C, msg_C) + 1

Limitation: L(a) < L(b) does NOT imply a happened-before b
            (could be concurrent events with coincidental ordering)
Vector Clocks — Detecting Causality
Node A: [1,0,0] → [2,0,0] → send([2,0,0]) ──────→ [4,0,0]
Node B: [0,1,0] → recv → [2,2,0] → [2,3,0] → send([2,3,0])
Node C: [0,0,1] ────────────────────→ recv → [2,3,2] → [2,3,3]

Causality detection:
  [2,0,0] → [2,2,0]  (A caused B's event: all A's slots ≤ B's)
  [2,3,0] vs [4,0,0]  CONCURRENT (neither dominates the other)

Conflict resolution on concurrent writes:
  • Application-level merge (CRDTs)
  • Last-Writer-Wins (LWW) — use physical timestamp as tiebreaker
  • Return both versions to client (Riak "siblings")
NTP Limitations: Network Time Protocol syncs clocks to ~1-10ms on LAN, ~100ms on WAN. Problems: (1) Clock skew — different rates of drift between machines. (2) Clock jumps — NTP can step clock backward. (3) Monotonic vs wall-clock — use monotonic for measuring durations, wall-clock only for human display. (4) Leap seconds — can cause 1s jump. Solution: leap smear (Google spreads over 24h).
Practical Guidance: Use Lamport timestamps when you only need total ordering (Kafka offsets). Use Vector clocks when you need to detect conflicts (DynamoDB, Riak). Use HLC when you need causality + wall-clock proximity (CockroachDB MVCC). Use TrueTime if you have GPS/atomic clocks (Spanner).

Replication Strategies

Copying data across nodes for fault tolerance and read scalability. The fundamental tradeoff: consistency vs availability vs latency.

Replication Topologies Compared
Single-Leader Leader Follower 1 Follower 2 Follower 3 Writes → Leader only Reads → Any replica ✓ No write conflicts ✓ Simple consistency model ✗ Leader is write bottleneck ✗ Failover downtime Postgres, MySQL, MongoDB, Kafka Multi-Leader Leader A Leader B async sync F1 F2 F3 Writes → Any leader ⚠️ Conflicts possible! ✓ Write availability (no single leader) ✓ Low latency (write to local DC) ✗ Conflict resolution needed ✗ Complex (write ordering unclear) CouchDB, Tungsten, multi-DC setups Google Docs (OT), Figma (CRDTs) Leaderless N1 N2 N3 N4 N5 Client writes to W nodes Client reads from R nodes W + R > N → strong consistency ✓ No leader = no failover ✓ High write availability ✓ Tunable consistency (W, R, N) ✗ Stale reads possible (if R+W≤N) ✗ Conflict resolution needed Cassandra, DynamoDB, Riak, Voldemort
Synchronous vs Asynchronous Replication
AspectSynchronousAsynchronousSemi-Synchronous
Write LatencyHigh (wait for all/majority replicas)Low (return after local write)Medium (wait for 1 replica)
DurabilityStrong (data on multiple nodes)Weak (data loss on leader crash)Good (1 replica guaranteed)
AvailabilityLower (blocked if replica down)Higher (leader independent)Balanced
ConsistencyStrong (all replicas up-to-date)Eventual (replication lag)Bounded staleness
Used ByRaft commit, SpannerPostgres streaming, MySQLMySQL semi-sync, Kafka (acks=1)
Conflict Resolution Strategies
StrategyHowProsConsUsed By
Last-Writer-Wins (LWW)Highest timestamp wins, discard othersSimple, deterministicData loss — concurrent writes silently droppedCassandra, DynamoDB
Vector Clocks + SiblingsDetect conflicts, return all versions to clientNo data lossClient must resolve; complexRiak, DynamoDB (optional)
CRDTsData structures that auto-merge (counters, sets, registers)Automatic, no coordinationLimited data types; space overheadRedis CRDT, Riak, Figma
Operational TransformTransform concurrent ops to preserve intentWorks for text editingComplex; centralized server often neededGoogle Docs
Application-levelCustom merge logic (e.g., union of shopping carts)Domain-specific correctnessDeveloper burdenAmazon shopping cart
When to Use Which Replication Strategy
ScenarioRecommendedWhy
Single-region, strong consistency neededSingle-leader, syncSimplest model, no conflicts, Raft/Paxos for HA
Multi-region, low-latency writesMulti-leaderWrite to local DC, async replicate; accept conflict resolution cost
High availability, tunable consistencyLeaderless (quorum)No single point of failure; tune W/R/N per use case
Read-heavy, eventual consistency OKSingle-leader, async replicasScale reads with followers; accept replication lag
Collaborative editingCRDTs or OTAutomatic conflict-free merging for concurrent edits
Replication Lag: In async replication, followers can be seconds behind leader. This causes: read-after-write inconsistency (user writes, reads from stale follower), monotonic read violations (time goes backward), causality violations (see reply before original message). Solutions: read-your-writes guarantee (route to leader after write), causal consistency (track dependencies).

Partitioning & Sharding

Split data across nodes to scale beyond a single machine. Key challenge: even distribution + efficient queries.

Hash Partitioning vs Range Partitioning
Hash Partitioning hash(key) % N user_123 → user_456 → user_789 → Partition 0 Partition 1 Partition 2 ✓ Even distribution (no hotspots) ✓ Good for point lookups ✗ Range queries require scatter-gather ✗ Adding nodes requires rehashing (unless consistent hash) Used by: Cassandra, DynamoDB, Redis Cluster, MongoDB (hashed) Hash functions: MD5, MurmurHash, xxHash Range Partitioning Key ranges: [A-F] [G-M] [N-Z] "Alice" → [A-F] "Karen" → [G-M] "Zara" → [N-Z] [A-F] [G-M] [N-Z] ✓ Efficient range queries (scan within partition) ✓ Sorted data within each partition ✗ Hotspots (e.g., all "S" names on one node) ✗ Uneven distribution without careful boundary selection Used by: HBase, BigTable, CockroachDB, Spanner, MongoDB (ranged)
Consistent Hashing with Virtual Nodes
Hash Ring [0, 2^32) A-1 A-2 A-3 B-1 B-2 B-3 C-1 C-2 C-3 k1 k2 How Consistent Hashing Works 1. Hash both keys and servers onto ring Key assigned to next server clockwise 2. Virtual nodes (vnodes) for balance Each physical server → 100-256 vnodes More vnodes = more even distribution 3. Adding a node: only K/N keys move vs hash(key)%N: ALL keys rehash! 4. Removing a node: keys go to next CW Minimal disruption to other nodes Key Benefit Adding/removing node moves only ~1/N of keys vs modulo hashing: adding node moves ~ALL keys Used by: Cassandra, DynamoDB, Memcached, Akamai CDN
Rebalancing Strategies
StrategyHowProsConsUsed By
Fixed PartitionsCreate many more partitions than nodes (e.g., 1000 partitions, 10 nodes). Assign partitions to nodes.Simple rebalancing (move whole partitions)Must choose partition count upfront; too few = large partitions, too many = overheadRiak, Elasticsearch, Couchbase
Dynamic SplittingStart with 1 partition per node. Split when too large, merge when too small.Adapts to data size; no upfront decisionComplex; split/merge coordinationHBase, RethinkDB, MongoDB
Proportional to NodesFixed number of partitions per node. New node steals random partitions from existing nodes.Balanced as cluster growsRandom splits can create uneven sizesCassandra (vnodes)
Cross-Partition Queries & Scatter-Gather
Scatter-Gather Pattern: Query that spans multiple partitions: (1) Scatter — coordinator sends query to all relevant partitions in parallel. (2) Gather — coordinator collects results, merges, sorts, returns to client. Problem: tail latency — response time = slowest partition. Mitigation: hedged requests (send to multiple replicas, use first response).
Secondary Indexes on Partitioned Data: Two approaches: (1) Local index (document-partitioned) — each partition maintains its own index. Writes are fast (single partition), reads require scatter-gather. (2) Global index (term-partitioned) — index itself is partitioned by term. Reads hit single partition, writes must update multiple index partitions (async, eventually consistent). Used by: DynamoDB (local), Elasticsearch (global).
// Scatter-Gather Example (Elasticsearch)
GET /users/_search { "query": { "range": { "age": { "gte": 25, "lte": 35 } } } }

Coordinator → Shard 0: search(age 25-35) → [doc1, doc5]
Coordinator → Shard 1: search(age 25-35) → [doc3, doc8]
Coordinator → Shard 2: search(age 25-35) → [doc2]
Coordinator: merge + sort → [doc1, doc2, doc3, doc5, doc8] → Client

Failure Detection

Detecting node failures in an asynchronous network is impossible to do perfectly (FLP). All detectors trade off detection speed vs false positive rate.

Heartbeat-Based Failure Detection Timeline
Node A Node B (monitor) HB HB HB 💥 CRASH expected HB missed missed Timeout = 3 × heartbeat_interval ⚠️ NODE SUSPECTED Trigger: failover / remove t=0s t=1s t=2s t=3s t=4s t=5s Detection time: ~2-3s
Phi Accrual Failure Detector
Problem with fixed timeouts: Network latency varies. A fixed timeout (e.g., 5s) either: (1) too short → false positives (healthy node marked dead during GC pause), or (2) too long → slow detection (actual failures take too long to detect).
Phi (φ) Accrual Detector: Instead of binary alive/dead, outputs a suspicion level φ (continuous value). Higher φ = more likely dead. Application chooses threshold (e.g., φ > 8 = dead). How it works: (1) Track inter-arrival times of heartbeats. (2) Compute mean and variance of arrival distribution. (3) φ = -log₁₀(P(next heartbeat hasn't arrived yet)). (4) φ grows exponentially with time since last heartbeat. Adaptive: automatically adjusts to network conditions — works on both LAN (low latency) and WAN (high latency) without tuning.
// Phi Accrual — Conceptual
φ(t_now) = -log₁₀(1 - F(t_now - t_last))
where F = CDF of normal distribution fitted to heartbeat intervals

Example: mean_interval = 1000ms, std_dev = 200ms
  t_now - t_last = 1000ms → φ ≈ 0.3  (probably alive)
  t_now - t_last = 2000ms → φ ≈ 3.0  (suspicious)
  t_now - t_last = 5000ms → φ ≈ 12.0 (almost certainly dead)

Threshold: φ > 8 → mark as dead (Cassandra default)
           φ > 12 → very conservative (fewer false positives)
SWIM Protocol — Gossip-Based Failure Detection
SWIM (Scalable Weakly-consistent Infection-style Membership): Combines failure detection with membership dissemination via gossip. Steps: (1) Node A picks random node B, sends ping. (2) If B responds → alive. (3) If B doesn't respond within timeout → A picks K random nodes, asks them to ping-req(B) (indirect probe). (4) If any indirect probe succeeds → B is alive (was just network issue between A and B). (5) If all fail → B marked as suspected. (6) After suspicion timeout → B marked dead. (7) Membership changes piggybacked on ping/ack messages (gossip dissemination).
SWIM Properties: O(1) per-node load (each node probes 1 random peer per interval). O(log N) detection time (gossip convergence). False positive rate tunable via K (indirect probes) and suspicion timeout. Used by: HashiCorp Memberlist (Consul, Nomad, Serf), Uber Ringpop.
Detection Time vs False Positive Tradeoff
DetectorDetection TimeFalse Positive RateScalabilityAdaptivityUsed By
Fixed Timeouttimeout value (e.g., 5s)High if timeout too shortO(N) messages from monitorNone — manual tuningSimple systems, Redis Sentinel
Heartbeat + Leaselease_duration (e.g., 10s)Low (conservative timeout)O(N) per monitorNoneZooKeeper sessions, Chubby
Phi AccrualAdaptive (based on history)Tunable via φ thresholdO(N) per monitorSelf-adjustingCassandra, Akka Cluster
SWIM (Gossip)O(log N) protocol periodsLow (indirect probes reduce)O(1) per nodeModerateConsul, Serf, Memberlist
SWIM + SuspicionO(log N) + suspicion timeoutVery lowO(1) per nodeGoodConsul (Lifeguard)
Design Guidance: For small clusters (3-7 nodes): simple heartbeat with Raft-style election timeout (150-300ms) works well. For medium clusters (10-100 nodes): Phi Accrual gives best accuracy. For large clusters (100+ nodes): SWIM/gossip is essential — O(1) per-node overhead vs O(N) for centralized heartbeat. Always add suspicion period before declaring dead — reduces false positives from transient network issues or GC pauses.