Welcome to the next lesson in our journey through distributed systems. In our previous session, we designed a high-availability system using leader-follower replication. We discovered that the choice of replication mode—asynchronous, synchronous, or semi-synchronous—forced us into a trade-off. Asynchronous replication, for example, gave us high performance but introduced replication lag, meaning followers could serve stale data. This temporary inconsistency is a fundamental concept in distributed systems.
Today, we will formally explore this concept by comparing different consistency models. You will learn to differentiate between strong, eventual, and causal consistency, understanding the guarantees each model provides and, crucially, when to use them. Mastering these models is non-negotiable for designing systems that are not only scalable but also correct for their specific business purpose.
1. The Consistency Spectrum
In distributed systems, consistency is not a binary switch (on/off) but a spectrum of guarantees. A consistency model is a contract between a data store and the applications that use it. It defines the rules about what state a read operation will see, especially after a write.
-
Technical Explanation:
The need for different models stems from the CAP Theorem, which you may recall states that a distributed system can only provide two of the following three guarantees simultaneously:- Consistency: Every read receives the most recent write or an error.
- Availability: Every request receives a (non-error) response, without the guarantee that it contains the most recent write.
- Partition Tolerance: The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes.
Since network partitions are a fact of life in any large-scale system, we are almost always forced to choose between Consistency and Availability. This choice directly maps to the consistency model we adopt. Opting for availability during a partition leads to weaker consistency models, while prioritizing consistency may mean the system becomes unavailable.
-
Metaphor for a 5-Year-Old:
Imagine you and your friends live in different houses (servers) and share a storybook.- Strong Consistency is like having a magic book that updates instantly for everyone the moment someone writes a new sentence. Every time you open the book, you see the absolute latest version.
- Eventual Consistency is like sharing updates via mail. When you write a new sentence, you mail a copy to your friends. It will get there eventually, but for a while, some friends will have the old version while you have the new one.
- Causal Consistency is like a group chat. If you reply to a friend's message, your reply will always appear after their message. But messages from a different, unrelated conversation might pop up in between. The order of related things is preserved.
2. Strong Consistency (Linearizability)
Strong consistency is the most intuitive model because it makes a distributed system behave like a non-distributed one (i.e., a single machine).
- Technical Explanation:
Strong consistency, often called Linearizability, provides the guarantee that every read will return the value of the most recently completed write. All operations (reads and writes) appear to have executed atomically at a single point in time in a single, global order. This is the "C" in the CAP theorem. To achieve this, a write operation must be propagated to and acknowledged by all (or a quorum of) replicas before the system sends an "OK" to the client. This is exactly what we saw with synchronous replication in the last lesson.

- Real-World Context & Trade-offs:
This model is essential for systems where correctness is non-negotiable and the cost of inconsistency is high.- Use Cases: Banking systems (you can't see an old balance after a deposit), e-commerce inventory management (to prevent overselling), and reservation systems.
- Pros: Simple to reason about; data is always correct and up-to-date.
- Cons: High latency for writes (due to the coordination overhead) and lower availability (if a replica is down or slow, writes can be blocked).
To understand the decision-making process, let's explore why you'd choose Strong Consistency in some scenarios and not others.
Eventual Consistency vs. Strong Consistency | How to decide between the two in System Design
The video 'Eventual Consistency vs. Strong Consistency' provides an excellent framework for deciding between models. We'll start by watching the sections that justify the need for strong consistency.
Watch the following two segments: the TinyURL example (01:48 - 03:46) and the Amazon inventory example (12:57 - 15:53). For each, focus on the speaker's analysis of why eventual consistency would negatively impact functional correctness and user experience, thus making strong consistency necessary.
3. Eventual Consistency
Eventual consistency is at the other end of the spectrum. It prioritizes availability and performance over immediate consistency.
- Technical Explanation:
The system guarantees that if no new updates are made to a data item, all accesses to that item will eventually return the last updated value. It does not specify when this will happen. This means for a period of time (the "inconsistency window"), different clients reading from different replicas may see different values for the same data item. This model is a direct consequence of choosing Availability and Partition Tolerance (AP) in the CAP theorem and is what you get with asynchronous replication.
The Art of Eventual Consistency in Distributed Systems
To go deeper, let's read about the mechanics and rationale for choosing eventual consistency from the article 'Consistency Patterns in Distributed Systems'.
Read the section titled 'The Art of Eventual Consistency in Distributed Systems'. Pay attention to how it links the model to the CAP theorem and the trade-offs regarding availability and scalability.
-
Real-World Context & Trade-offs:
This model is perfect for use cases where temporary staleness has a low business impact.- Use Cases: Social media "likes" or "view" counts, DNS records, user profile updates, and product recommendations. It's acceptable if a like count is slightly off for a few seconds.
- Pros: Low latency for reads and writes, and high availability. The system can continue to accept writes even if some replicas are temporarily disconnected.
- Cons: Complex to reason about for developers. Reading stale data can lead to a confusing user experience if not handled carefully.
-
Python Code Snippet:
This code simulates an eventually consistent key-value store. Thewriteoperation returns immediately, while a background thread handles the slow replication. Areadfrom a specific replica might see old data until replication completes.import time import threading class EventuallyConsistentStore: def __init__(self, replica_count=3, replication_delay=2): # Each replica is a separate dictionary self.replicas = [{} for _ in range(replica_count)] self.leader = self.replicas[0] # Writes go to the leader (replica 0) self.replication_delay = replication_delay print(f"Initialized {replica_count} replicas with a {replication_delay}s replication delay.") def write(self, key, value): """Write to the leader and return immediately.""" print(f"\nCLIENT: Writing '{key}={value}' to leader.") self.leader[key] = value print("LEADER: Write accepted. Acknowledging client immediately.") # Asynchronously replicate to followers in the background replication_thread = threading.Thread(target=self._replicate, args=(key, value)) replication_thread.start() return "OK" def _replicate(self, key, value): """Simulates slow replication to followers.""" print(f"REPLICATION_DAEMON: Starting replication of '{key}={value}' to followers...") time.sleep(self.replication_delay) for i, replica in enumerate(self.replicas[1:], 1): replica[key] = value print(f"REPLICATION_DAEMON: Replicated to Replica-{i}.") print("REPLICATION_DAEMON: Replication complete.") def read(self, key, replica_id): """Read a key from a specific replica.""" if not 0 <= replica_id < len(self.replicas): return "Error: Invalid replica ID" value = self.replicas[replica_id].get(key, 'None') print(f"CLIENT: Reading '{key}' from Replica-{replica_id}. Value: {value}") return value # --- Simulation --- store = EventuallyConsistentStore() # Client writes a value. Gets an immediate OK. store.write('user:123:name', 'Alice') # Immediately try to read from all replicas print("\n--- Reading immediately after write ---") store.read('user:123:name', replica_id=0) # Leader has the new value store.read('user:123:name', replica_id=1) # Follower has stale data store.read('user:123:name', replica_id=2) # Follower has stale data # Wait for replication to complete print("\n--- Waiting for replication delay to pass ---") time.sleep(3) # Read again from all replicas print("\n--- Reading after replication ---") store.read('user:123:name', replica_id=0) # Leader store.read('user:123:name', replica_id=1) # Follower is now consistent store.read('user:123:name', replica_id=2) # Follower is now consistent
4. Causal Consistency
Causal consistency is a pragmatic compromise between strong and eventual models. It's stronger than eventual but weaker than strong, providing an ordering guarantee that aligns well with human intuition.
-
Technical Explanation:
Causal consistency ensures that operations which are causally related are seen in the same order by all processes. Operations that are concurrent (not causally related) can be seen in different orders by different replicas.What is a causal relationship?
- A read that happens after a write on the same process is causally related.
- A write that happens after a read (of some value
x) is causally related to the write that created valuex. - Causality is transitive: If A causes B, and B causes C, then A causes C.
This is typically implemented "under the hood" using mechanisms like vector clocks to track the dependency chain of operations.

- Real-World Context & Trade-offs:
This model is ideal for applications where the order of related actions matters, but a global, system-wide order is unnecessary.- Use Cases: Comment threads on social media (a reply must always be seen after the comment it's replying to), collaborative editing, and direct messaging systems.
- Pros: Provides a more intuitive user experience than eventual consistency without the high performance cost of strong consistency. It balances performance and logical correctness.
- Cons: More complex to implement than eventual consistency. Requires tracking causal dependencies.
Let's watch a short, clear explanation of this model.
Consistency Models | System Design | Distributed Systems
The 'Consistency Models' video offers a great, concise explanation of Causal Consistency with a practical example.
Watch from 04:26 to 07:16. Focus on the definition of a causal relationship and how the social media comment-reply example demonstrates the principle.
5. Elite Interview Deep Dive: The Decision Framework
In a system design interview, stating the definition of a model is not enough. You must justify your choice based on the specific requirements of the system being designed. An excellent way to structure your answer is to analyze the impact of your choice on three key areas.
The Framework: When is it OK to relax from Strong to Eventual Consistency?
Ask yourself what happens to the system's...
- Functional Correctness: Does the system still work as intended? For an inventory system, eventual consistency leads to overselling, so it's not functionally correct. For Twitter likes, it is.
- Reliability: Does the weaker model introduce new failure modes or instability? For TinyURL, if a user gets a URL that immediately returns a 404, they might retry the creation, putting extra load on the system.
- User Experience: Is the user's interaction with the system confusing or jarring? Seeing your own profile picture revert to the old one after an update (
Read-Your-Writesviolation, a common issue in eventually consistent systems) is a bad user experience.
Here is a summary table comparing the models:
| Model | Guarantees | Pros | Cons | Best For... |
|---|---|---|---|---|
| Strong | Reads see the latest completed write. Acts like a single machine. | Simple to reason about, always correct data. | High latency, low availability for writes. | Financial transactions, inventory, booking systems. |
| Causal | Reads see causally-related writes in order. Concurrent writes can be reordered. | Intuitive ordering, good performance balance. | More complex to implement than eventual. | Comment threads, chat applications, collaborative editing. |
| Eventual | If writes stop, all replicas will eventually converge to the same value. | Very low latency, very high availability. | Can read stale data, complex for developers. | Social media analytics, user profiles, DNS, content delivery. |
Test your understanding! (Interview-Style Question)
You are designing a collaborative document editor like Google Docs. Multiple users can edit the same document simultaneously. Which consistency model would you choose as your foundation and why? Discuss the trade-offs and potential challenges with your choice.
Show answer
For a collaborative editor like Google Docs, I would base my design on Causal Consistency, likely enhanced with features to achieve what is sometimes called Causal+ Consistency.
Justification:
-
Why not Strong Consistency? If we used strong consistency, every single keystroke from any user would have to be synchronously replicated and agreed upon by a quorum of servers before it appeared on anyone's screen. This would introduce unacceptable latency, making real-time typing feel sluggish and unresponsive. It would also suffer from low availability; a network partition could block all users from editing.
-
Why not simple Eventual Consistency? Pure eventual consistency is too weak. It doesn't preserve the order of related operations. For example, if I type the sentence "The quick brown fox" and my edits arrive at a collaborator's machine out of order, they might see "fox brown quick The". More subtly, if I correct a typo (delete a character, then insert another), those two operations are causally related. If they are reordered, the document state becomes corrupted.
-
Why Causal Consistency is the right fit: Causal consistency provides the perfect middle ground. It ensures that edits that depend on each other (like a sequence of typing from one user, or a reply to a comment) are seen in the correct order by everyone. However, concurrent edits from two different users on different parts of the document can be processed in parallel and merged, offering excellent performance and a responsive feel.
Challenges and Enhancements (The "Causal+" part):
The main challenge with any model weaker than strong consistency is handling conflicts from concurrent operations. For example, what if two users edit the exact same word at the same time?
To solve this, we need to go beyond basic causal consistency and use specific data structures and algorithms, such as:
- Conflict-Free Replicated Data Types (CRDTs): These are special data structures designed to be merged automatically without conflicts. For text, this could be a CRDT that represents the document as an ordered list of characters, where each character has a unique ID, allowing insertions and deletions to be resolved deterministically.
- Operational Transformation (OT): This is another popular algorithm (historically used by Google Docs) where operations are transformed based on concurrent operations that have already been applied, ensuring all users converge to the same state.
So, my final answer is to use Causal Consistency to preserve logical ordering, and a conflict resolution strategy like CRDTs or OT to handle concurrent edits and guarantee eventual convergence for all users. This provides the intuitive, real-time experience users expect while remaining highly available and performant.
Conclusion
You have now explored the critical spectrum of consistency models that govern distributed data stores. You've seen that the choice is not just a technical detail but a core architectural decision that reflects the fundamental trade-offs between correctness, performance, and availability.
Key Takeaways:
- Strong Consistency (Linearizability): Provides the simplest mental model (acts like one machine) at the cost of performance and availability. Essential for systems where data must be perfectly accurate at all times.
- Eventual Consistency: Prioritizes availability and speed, guaranteeing that data will converge over time. Ideal for use cases where temporary staleness is acceptable.
- Causal Consistency: Offers a powerful middle ground, preserving the logical "cause-and-effect" order of operations, which aligns well with user expectations in collaborative applications.
- The choice is a trade-off: Your decision must be driven by business requirements, analyzing the impact on functional correctness, reliability, and user experience.
Next Lesson Preview
In our last lesson, we identified that a critical part of a failover process is leader election. In this lesson, we saw that strong consistency often requires coordination and agreement among servers. How do a group of distributed servers reliably agree on anything—be it who the new leader is, or what the latest committed value is—especially in the face of network failures and delays? This is the famous distributed consensus problem. In our next lesson, we will tackle this head-on by studying the Raft algorithm, an understandable and widely used protocol designed to achieve consensus.