Consistency models define the rules about how and when updates to distributed data become visible to readers. Understanding these models is crucial for designing distributed systems, as they represent fundamental tradeoffs between performance, availability, and the guarantees provided to applications and users.
Strong Consistency
Strong consistency, also called linearizability, provides the illusion that operations happen atomically at a single point in time. Once a write completes, all subsequent reads return that value, regardless of which replica services the request. This matches our intuitive understanding of how data should behave.
Implementing strong consistency requires coordination across replicas. Before confirming a write, the system must ensure all (or a majority of) replicas have received it. This coordination introduces latency proportional to network round-trip time and reduces availability, as writes can’t complete if enough replicas are unreachable.
Traditional databases like PostgreSQL default to strong consistency within a single node. Distributed databases like Google Spanner achieve strong consistency across geographic regions through sophisticated protocols, though with increased latency for writes.
When to Use: Choose strong consistency for financial transactions, inventory management, or any case where stale or inconsistent data causes correctness issues. The performance cost is worthwhile when consistency is non-negotiable.
Eventual Consistency
Eventual consistency guarantees that, given enough time without new updates, all replicas will converge to the same state. However, immediately after a write, different replicas might return different values. Reads might not reflect recent writes, and different readers might see different values temporarily.
This weaker guarantee enables better performance and availability. Writes can complete without waiting for cross-replica coordination. Replicas accept operations even when disconnected, synchronizing later. The system remains available during network partitions.
Many large-scale systems use eventual consistency: Amazon’s shopping cart, DNS, Cassandra, and DynamoDB. For these systems, availability and performance outweigh the temporary inconsistency.
When to Use: Choose eventual consistency for high-scale systems where availability matters more than immediate consistency. Social media feeds, product catalogs, and view counts tolerate eventual consistency well.
Causal Consistency
Causal consistency preserves cause-and-effect relationships. If operation A causally influences operation B (for example, B reads a value written by A), all nodes see A before B. However, concurrent operations without causal relationships might be seen in different orders by different nodes.
This is stronger than eventual consistency but weaker (and cheaper) than strong consistency. It provides an intuitive model: related operations stay in order, but unrelated operations can appear in any order.
Implementing causal consistency typically uses version vectors or similar mechanisms to track causality. Operations include metadata about what operations they depend on, allowing the system to maintain causal order.
When to Use: Choose causal consistency when operation ordering matters for related operations but strong consistency is too expensive. Social media comments and replies benefit from causal consistency: replies always appear after the posts they respond to.
Session Consistency
Session consistency provides guarantees within a single client session. A user’s own operations appear consistent and ordered, but different users might see different views of the data.
Read Your Writes ensures a user sees their own updates. After posting a comment, the user immediately sees their comment even if other users don’t yet. This prevents the jarring experience of writing data and not seeing it reflected.
Monotonic Reads ensures a user never sees older data after seeing newer data. Once you’ve seen version 5 of a document, you’ll never see version 3, preventing time going backward from the user’s perspective.
Monotonic Writes ensures a user’s writes are applied in order. If you update your profile twice, those updates apply in the order you made them, never reversed.
Session consistency is practical for many applications. Different users can see slightly different views (eventual consistency across users) while each user experiences a consistent view (strong consistency within a session).
When to Use: Choose session consistency for user-facing applications where each user needs consistency for their own actions but global consistency isn’t required. Many web applications naturally fit this model.
Bounded Staleness
Bounded staleness guarantees that reads aren’t too stale, limited by either time or version lag. For example, reads might lag writes by at most 5 seconds or at most 100 updates. This provides a quantifiable consistency guarantee between strong and eventual consistency.
Azure Cosmos DB offers bounded staleness as a consistency level. You can specify maximum staleness in time or operations, and the system ensures reads stay within those bounds.
When to Use: Choose bounded staleness when you need predictable consistency but can tolerate some lag. Stock prices could use bounded staleness: 5-second-stale prices are acceptable, but hour-old prices are not.
Quorum Consistency
Quorum-based consistency configures the number of replicas that must agree for operations to succeed. With N replicas, reads from R replicas and writes to W replicas provide consistent results when R + W > N.
For example, with 5 replicas, requiring 3 for reads and 3 for writes guarantees consistency: any read of 3 replicas overlaps with the 3 replicas that confirmed the write, ensuring at least one replica has the latest value.
Tuning R and W allows tradeoffs. High R means slower reads but faster writes; high W means slower writes but faster reads. R=W=majority provides good balance. R=1, W=N optimizes for read performance; R=N, W=1 optimizes for write performance but at the cost of consistency.
Systems like Cassandra and DynamoDB allow per-operation quorum configuration, letting you choose consistency levels based on specific operation requirements.
Serializability
Serializability means concurrent transactions produce results equivalent to some serial execution, though not necessarily the same serial order each time. This is the gold standard for transaction consistency.
Strict Serializability adds the constraint that the equivalent serial order respects real-time ordering: if transaction A completes before transaction B starts, A appears before B in the serial order. This combines serializability with linearizability.
Achieving serializability typically requires sophisticated concurrency control like two-phase locking or optimistic concurrency control. The performance cost is substantial, but the correctness guarantees are strong.
When to Use: Choose serializability for complex transactions where correctness is paramount. Banking systems, reservation systems, and any application with intricate business rules benefit from serializability.
Practical Considerations
Most systems don’t offer just one consistency model. They provide multiple consistency levels that you can choose per operation. DynamoDB offers eventual and strong consistency for reads. Cassandra offers consistency levels from ONE (weak) to ALL (strong).
Performance Tradeoffs are significant. Strong consistency requires coordination, adding latency and reducing availability. Eventual consistency allows high performance but complicates application logic to handle stale or conflicting data.
Application Complexity differs by model. Strong consistency simplifies application code: data is always current and consistent. Weaker models require application logic to handle stale data, conflicts, and consistency anomalies.
Network Conditions affect model choice. Multi-region systems experience higher latency and more partitions, making strong consistency more expensive. Single-datacenter systems can afford stronger consistency with less impact.
Choosing a Consistency Model
Start by understanding your application’s actual consistency requirements, not what seems ideally safe. Many use cases tolerate weaker consistency, and the performance benefits are substantial.
Consider consistency requirements per data type, not globally. User profiles might need session consistency while view counts can be eventually consistent. Mix consistency models within the same application.
Test with weak consistency from the start. Applications developed assuming strong consistency often have subtle bugs when moved to eventually consistent systems. Design and test with your intended consistency model from the beginning.
Monitor consistency metrics: lag between write and read visibility, conflict rates, and user-reported consistency issues. This reveals whether your chosen consistency model meets actual requirements.
Consistency models represent fundamental tradeoffs in distributed systems. Understanding these models and their implications enables informed architectural decisions that balance performance, availability, and correctness for your specific requirements. The goal isn’t always the strongest consistency, but rather the appropriate consistency for each use case.