Patterns of Distributed Systems Link to heading
Based on: Catalog of Patterns of Distributed Systems by Unmesh Joshi (published on martinfowler.com, Nov 2023)
Table of Contents Link to heading
Group G — Data Propagation & Observation Link to heading
These patterns handle how information spreads through a cluster and how clients track cluster state changes.
G1. Gossip Dissemination Link to heading
Spread information through the cluster like an epidemic — without a central broker.
Problem Link to heading
In a large cluster (hundreds or thousands of nodes), you need to disseminate information to all nodes (e.g., “Node X has failed,” “the new cluster configuration”). Broadcasting to every node is O(N) messages from a single source — it floods the network and creates a bottleneck.
Solution Link to heading
Each node periodically picks a random subset of peers and exchanges state with them. Each peer then spreads the information to other random peers. Information propagates exponentially fast (like a rumor spreading through a crowd) with no central coordinator.
How it works Link to heading
Time 0: Node A knows new info
Time 1: A gossips to [B, E] → B and E learn it
Time 2: B gossips to [C, F], E gossips to [D, G] → 6 nodes know
Time 3: C, D, F, G gossip to others → 14 nodes know
...
After O(log N) rounds: all N nodes know
Each gossip message includes a version number or digest so nodes can tell what information is new vs. already known. This prevents infinite re-gossip.
Real-world analogy Link to heading
Office rumors. Person A tells two colleagues. Each of them tells two more. Within a few hours, the whole building knows — without anyone sending a company-wide broadcast.
Example systems Link to heading
Amazon Dynamo (membership and failure detection), Cassandra (cluster metadata), Consul, Riak, Bitcoin peer discovery
Trade-offs Link to heading
| Pro | Con |
|---|---|
| Highly scalable — no central bottleneck | Eventually consistent (not instant) — there’s a propagation delay |
| Fault-tolerant — works even if many nodes are down | Hard to guarantee a specific delivery time |
| No single point of failure | Information may be slightly stale at any given node |
| Self-healing — new nodes quickly learn cluster state | Verbose — generates constant background traffic |
Related patterns Link to heading
→ HeartBeat (often piggybacked in gossip messages) → Version Vector / Versioned Value (for deduplication in gossip) → Emergent Leader (uses gossip for membership info) → Consistent Core (alternative to gossip for strongly consistent metadata)
G2. Follower Reads Link to heading
Scale read throughput by serving reads from follower nodes.
Problem Link to heading
In a Leader and Followers setup, all writes and strong reads go to the leader. As read traffic grows, the leader becomes a bottleneck. You have multiple follower nodes sitting idle for reads.
Solution Link to heading
Allow clients to read from follower nodes. Followers may be slightly behind the leader (stale data), but for many use cases, slightly stale reads are acceptable — and the throughput gain is significant.
How it works Link to heading
Write path: Client → Leader → replicate to followers
Read path:
- Strong read: Client → Leader (always up-to-date)
- Follower read: Client → any Follower (may be slightly stale)
Client can specify: read-my-own-writes?
If yes: read from leader, or wait for follower to catch up to your last write's index
If no: any follower is fine
Read-your-own-writes consistency: After a write, the client can pass the log index of their write to the follower. The follower waits until it has applied entries up to that index before responding.
Real-world analogy Link to heading
A company’s website: the main database handles all updates. Reporting dashboards and analytics pages can read from a replica that’s a few seconds behind — nobody cares if the “total users” count is 3 seconds stale.
Example systems Link to heading
MySQL read replicas, MongoDB secondary reads, Cassandra (tunable consistency), CockroachDB follower reads
Trade-offs Link to heading
| Pro | Con |
|---|---|
| Linear read throughput scaling with cluster size | Reads may be stale (replication lag) |
| Reduces leader load dramatically | Read-your-own-writes requires extra bookkeeping |
| Geographic distribution (read from nearby replica) | Strong consistency requires going to leader |
Related patterns Link to heading
→ Leader and Followers → High-Water Mark (follower knows how far behind it is) → Versioned Value (client can request specific version for consistency)
G3. State Watch Link to heading
Push notifications: tell me when something changes.
Problem Link to heading
Clients often need to react to changes in cluster state (e.g., “tell me when the leader changes,” “tell me when a configuration key is updated”). Polling — repeatedly asking “has it changed?” — is wasteful: it generates load even when nothing has changed and adds latency to detect changes.
Solution Link to heading
Clients register a watch (subscription) on a specific key or path in the consistent store. When that key’s value changes, the server pushes a notification to all registered watchers. No polling required.
How it works Link to heading
Client A: "Watch key /config/leader"
→ Server registers watch: {key: "/config/leader", callback: A.notify}
[Some time later...]
New leader elected → Server writes "/config/leader" = "Node5"
Server iterates watches for "/config/leader":
→ Sends notification to Client A: {key: "/config/leader", newValue: "Node5"}
Client A receives notification → updates its cached leader address
→ Client A can re-register the watch if it wants future notifications
Watches are typically one-shot: they fire once and must be re-registered. This prevents memory leaks from forgotten watches.
Real-world analogy Link to heading
A stock price alert: you set an alert at “$AAPL crosses $200.” Your broker notifies you once when it crosses — you don’t have to check the price every second.
Example systems Link to heading
ZooKeeper (watches), etcd (watch API), Kubernetes controller-manager (watches the API server), Consul watches
Trade-offs Link to heading
| Pro | Con |
|---|---|
| Event-driven — eliminates polling overhead | Missed events if the client is disconnected during a change |
| Immediate reaction to changes | Watch re-registration overhead |
| Natural fit for reactive/event-driven architectures | Server must track all registered watches (memory) |
Related patterns Link to heading
→ Consistent Core (provides the watch service) → Lease (watches combined with leases implement leader election in ZooKeeper)