Distributed systems comparison
Eventual vs Strong Consistency
One of the core trade-offs in distributed systems design. Strong consistency feels natural and safe; eventual consistency unlocks global scale and high availability. Understanding the difference is essential for any backend engineer.
TL;DR
- Strong consistency — every read returns the latest write. All nodes agree immediately. Simpler to reason about but sacrifices availability and latency under network partitions. Think Postgres, etcd, Zookeeper.
- Eventual consistency — replicas converge to the same value over time. Reads may return stale data briefly. Enables higher availability, lower latency, and geographic distribution. Think DynamoDB, Cassandra, DNS.
- The CAP theorem forces a choice: in the presence of a network partition you can have consistency or availability — not both simultaneously.
Side-by-side comparison
| Aspect | Strong Consistency | Eventual Consistency |
|---|---|---|
| Guarantee | Every read returns the latest write | Replicas converge — reads may be stale briefly |
| Availability | May reject requests during partition (CP) | Always responds, may return stale data (AP) |
| Performance | Higher latency (coordination overhead) | Lower latency (local reads) |
| CAP position | CP — Consistency + Partition tolerance | AP — Availability + Partition tolerance |
| Data model | ACID transactions | BASE (Basically Available, Soft state, Eventually consistent) |
| Geo-distribution | Hard — cross-region consensus is slow | Easy — replicas accept writes locally |
| Use case | Finance, inventory, seat booking | Social feeds, DNS, shopping carts, caches |
| Examples | Postgres, MySQL, CockroachDB, etcd | DynamoDB (default), Cassandra, Couchbase, DNS |
Code side-by-side
Reading data with different consistency levels:
Strong consistency (Postgres transaction)
BEGIN;
-- Locks the row; no other transaction
-- can read a stale value while we write
SELECT balance FROM accounts
WHERE id = 42 FOR UPDATE;
UPDATE accounts
SET balance = balance - 100
WHERE id = 42;
COMMIT;
-- Reader now sees 100 less, guaranteed. Eventual consistency (DynamoDB)
// Default: eventually consistent read
// (may return data up to 1 second old)
const result = await dynamo.getItem({
TableName: 'Accounts',
Key: { id: { N: '42' } },
}).promise();
// Strongly consistent read (2x cost):
const result = await dynamo.getItem({
TableName: 'Accounts',
Key: { id: { N: '42' } },
ConsistentRead: true, // <-- opt in
}).promise(); When to choose Strong Consistency
- Financial transactions. Deducting from a balance, processing a payment, or transferring funds require that every participant sees the same current state.
- Inventory and seat reservations. Overselling happens when two concurrent reads see the same available quantity and both commit a purchase.
- Authentication and authorisation. After a user's permissions are revoked, the system must enforce that immediately — not eventually.
- Leader election and distributed locks. Only one node should believe it is the leader at any given time; etcd and Zookeeper provide this guarantee.
When to choose Eventual Consistency
- Social media feeds and timelines. Seeing a post appear a second late is invisible to users and saves enormous coordination cost at scale.
- DNS and configuration propagation. DNS records propagate across the internet over minutes; this is deliberate and well-understood.
- Shopping carts and wishlists. Losing an item from a cart due to a brief network partition is recoverable; blocking purchases during a partition is not.
- Geographically distributed systems. A system that spans continents must accept local writes immediately and sync later — the speed of light makes synchronous cross-region consensus impractical.
English phrases engineers use
Strong consistency conversations
- "We need ACID guarantees for the payment flow."
- "This query runs in a serialisable transaction."
- "The system is CP — it will reject writes during a partition."
- "We use compare-and-swap to avoid lost updates."
- "Postgres gives us linearisable reads within a transaction."
Eventual consistency conversations
- "There's a replication lag of a few hundred milliseconds."
- "The system is AP — it stays up but may serve stale data."
- "We use read-your-own-writes to make the UI feel consistent."
- "The replicas will converge once the partition heals."
- "We apply last-write-wins conflict resolution with vector clocks."
Quick decision tree
- Financial data, inventory, reservations → Strong Consistency
- Social feeds, product catalogues, recommendations → Eventual Consistency
- Must stay available during network partition → Eventual Consistency
- Multi-region writes with low latency → Eventual Consistency
- Access control, session invalidation → Strong Consistency
- Read-heavy, cache-friendly data → Eventual Consistency
- Distributed lock or leader election → Strong Consistency
Common Mistakes and Trade-offs
A pervasive mistake developers make when evaluating eventual consistency is prematurely optimizing for it. Teams often assume that simply 'embracing' eventual consistency will magically solve performance problems, leading to a cascade of poorly designed systems where queries are repeatedly retried or complex compensating transactions are built to handle minor data discrepancies. The core issue isn't the model itself but a lack of understanding about how to manage the inherent latency and potential conflicts. Focusing solely on 'eventual' without considering strategies like idempotent operations, optimistic locking, or bounded contexts often exacerbates problems rather than resolving them. It's almost always better to start with strong consistency and then explore eventual solutions if performance bottlenecks genuinely emerge—not as a default assumption.
At scale, the trade-off between strong and eventual consistency dramatically shifts. Initially, the latency differences might seem negligible. However, as the number of concurrent operations grows exponentially – think millions or billions – the cumulative effect of 'stale reads' in an eventually consistent system becomes significant. This isn't just about occasional inconsistencies; it's about a steadily degrading user experience. Furthermore, the increased complexity of managing distributed transactions and reconciliation processes to maintain strong consistency at that scale creates enormous operational overhead – often exceeding the initial perceived gains from reduced latency. The cost of maintaining strict serializability can quickly become prohibitive.
The misconception that 'strong consistency is always better' stems from a misunderstanding of its limitations. While it guarantees data accuracy, it fundamentally restricts system scalability and responsiveness. Strong consistency typically relies on techniques like two-phase commit (2PC), which introduces significant performance bottlenecks and reduces the availability of participating nodes. The latency introduced by these mechanisms can severely impact user experience, especially in geographically distributed systems. Eventual consistency, conversely, allows for greater throughput and fault tolerance by accepting temporary inconsistencies, but requires careful design to mitigate potential negative impacts on application logic.
Migrating between strong and eventual consistency isn't a simple flip of a switch; it's a complex architectural undertaking with significant implications. A naive approach – simply changing the data model – will almost certainly lead to disaster. The key is identifying bounded contexts where eventual consistency can be safely applied, while retaining strong consistency for critical operations like financial transactions or user authentication. Furthermore, hybrid approaches—using strong consistency for core services and eventual consistency for peripheral read-only data—are increasingly common. Successfully navigating this requires deep understanding of the application's requirements, thorough testing, and a robust monitoring strategy to detect and address any emerging inconsistencies.
Frequently asked questions
What is strong consistency in plain English?
Strong consistency means that after a write completes, every subsequent read — from any node in the system — returns that new value. There is a single, globally agreed-upon order of operations. It is the behaviour you expect from a single-machine relational database.
What is eventual consistency?
Eventual consistency means that if you stop writing to a key, all replicas will converge to the same value — eventually. Immediately after a write, some replicas may still return stale data. Amazon DynamoDB (by default), Apache Cassandra, and DNS are classic examples.
What does the CAP theorem say about these?
CAP theorem states that a distributed system can guarantee at most two of: Consistency, Availability, and Partition tolerance. Since network partitions are unavoidable, you choose CP (strong consistency, may reject requests during partition) or AP (eventual consistency, always responds, may be stale). Strong consistency = CP; eventual consistency = AP.
Is eventual consistency dangerous?
It depends on the use case. Eventual consistency is perfectly safe for a shopping cart, product catalogue, or social media feed — a slight lag is invisible to users. It is dangerous for financial ledgers, inventory reservation, or anything where acting on stale data causes real-world harm.
Can I get strong consistency from DynamoDB or Cassandra?
Yes, with trade-offs. DynamoDB offers strongly consistent reads (double the cost, higher latency). Cassandra lets you set QUORUM consistency on individual queries — a majority of nodes must agree, approximating strong consistency at the cost of latency and availability.
What is "read-your-own-writes" consistency?
Read-your-own-writes is a middle ground: you are guaranteed to see your own writes reflected immediately, but other users may still see stale data. Many eventually consistent systems offer this as a compromise — it is sufficient for most user-facing features where only the author needs instant feedback.