CAP theorem, consistency models, and replication lag in daily work
Eventual consistency is not a compromise for poorly built systems but a deliberate consequence of the CAP theorem in every distributed system, including read replicas in relational databases. Whoever concretely understands consistency models, conflict resolution, and replication lag makes better decisions about where a short delay is acceptable and where it is not.
Table of Contents
- 1. What eventual consistency really means
- 2. The CAP theorem as a starting point
- 3. Consistency models across the spectrum: from strong to eventual
- 4. Read-your-writes and session consistency as intermediate stages
- 5. Conflict resolution: last write wins, vector clocks, and CRDTs
- 6. Where eventual consistency is unproblematic and where it is not
- 7. Measuring and monitoring replication lag
- 8. Eventual consistency with read replicas in SQL databases
- 9. Consistency models in direct comparison
- 10. Summary
- 11. FAQ
1. What eventual consistency really means
Eventual consistency describes a consistency guarantee where a change is not immediately visible on all nodes of a distributed system, but is guaranteed to arrive everywhere after a finite time, provided no new changes come in. The term is often misunderstood as "the data is eventually correct at some point", but it is actually a precisely defined, weaker guarantee compared to strong consistency, where every read transaction is guaranteed to see the most recently written value.
Important to understand: eventual consistency is not a design weakness but a deliberate technical decision that enables a distributed system to achieve higher availability and lower latency, at the cost of temporarily differing views on the same record. This decision is not made only by NoSQL systems like Cassandra or DynamoDB, but by every relational database with asynchronous read replicas as well, something many SQL focused developers initially overlook.
This article explains eventual consistency starting from the CAP theorem, shows the spectrum of consistency models between strong and eventual, covers conflict resolution for concurrent write operations, and shows concretely how to measure and monitor replication lag in practice.
2. The CAP theorem as a starting point
The CAP theorem, formulated by Eric Brewer, states: a distributed system cannot fully guarantee consistency, availability, and partition tolerance simultaneously during a network partition, but must choose between consistency and availability, while partition tolerance is practically unavoidable in an actual distributed system. Exactly at this point, eventual consistency arises as a deliberate choice in favor of availability.
If a system chooses consistency during a network partition, it refuses read or write operations on an isolated node until the partition is resolved, in order to avoid risking contradictory states. If it chooses availability, every node continues answering requests, even with potentially stale data, and reconciles discrepancies only after the partition ends via eventual consistency. This decision is not a one time global configuration but can even be made per operation in modern systems.
3. Consistency models across the spectrum: from strong to eventual
Between strict, immediate consistency and pure eventual consistency lies a whole spectrum of intermediate models that offer different trade offs between correctness and availability. Strong consistency guarantees that every read operation immediately delivers the most recently written value, regardless of which node is read from, which usually requires coordination and therefore higher latency.
Bounded staleness guarantees that stale data lags behind the current state by at most a defined time span or a defined number of versions, a practical middle ground for applications that tolerate some delay but not an unlimited one. Monotonic read consistency guarantees that a client never sees an older state than before during consecutive reads, even if absolute freshness is not guaranteed. Pure eventual consistency sits at the weakest end of this spectrum, but offers the highest availability and lowest latency.
4. Read-your-writes and session consistency as intermediate stages
A particularly practice relevant intermediate stage is read your writes consistency: a client that has written a change is guaranteed to see that change on its next read operation, even if other clients do not yet see the change due to eventual consistency. This guarantee solves a very common UX problem: a user updates their profile picture and reloads the page, but still sees the old picture because the read operation happened to hit a replica that has not yet synchronized.
Session consistency typically implements read your writes via so called sticky routing: all requests of a user session are routed for a certain time to the same node, or at least to a node guaranteed to already know all write operations of that session, for example the primary instead of a replica right after a write. This technique solves the most common practical problem of eventual consistency, without giving up the availability advantages of a distributed system for all other requests.
-- Simulating session consistency in the application layer:
-- read from the primary for a limited time after a write instead of
-- from a replica that may not yet be synchronized
-- Write operation always on the primary
UPDATE user_profiles SET avatar_url = '/media/avatar-42-v3.webp'
WHERE user_id = 42;
-- Pseudocode for the routing decision in the application:
-- IF last_write_timestamp(session) < replica_lag_threshold THEN
-- route_to("primary")
-- ELSE
-- route_to("any_replica")
-- END IF
-- This way the writing user sees their new picture immediately,
-- while other readers continue to be served by replicas
5. Conflict resolution: last write wins, vector clocks, and CRDTs
Once several nodes accept write operations on the same record at the same time, a system with eventual consistency must define how conflicting versions get merged back together. The simplest strategy is last write wins: every write operation gets a timestamp, and in a conflict the version with the more recent timestamp wins, while the older one is silently discarded. This is easy to implement but can unnoticeably overwrite legitimate changes if clocks between nodes are not perfectly synchronized.
Vector clocks solve this problem more precisely: each node keeps its own counter, and comparing the vectors shows whether one version is actually causally older or whether it is a real, not automatically resolvable conflict that must be returned to the application or the user. Conflict free replicated data types, CRDTs for short, go a step further and define data structures whose operations are mathematically guaranteed to be commutative and associative, so that changes from several nodes always merge uniquely and automatically into the same final state, entirely without manual conflict resolution.
// Simplified example: last write wins on a conflict
// Two nodes write to the same record at nearly the same time
const writeA = { userId: 42, status: "away", timestamp: 1732000001200 };
const writeB = { userId: 42, status: "online", timestamp: 1732000001350 };
function resolveConflict(a, b) {
// The more recent timestamp wins, the older version is discarded
return a.timestamp > b.timestamp ? a : b;
}
const resolved = resolveConflict(writeA, writeB);
console.log(resolved.status); // "online", because timestamp is larger
// Risk: with imperfectly synchronized clocks the actually more
// recent change can be incorrectly discarded
6. Where eventual consistency is unproblematic and where it is not
Whether eventual consistency is acceptable depends exclusively on the consequences of a brief discrepancy, not on a general rule. For like counters, view counts, product recommendations, or activity feeds, a delay of a few seconds to milliseconds is practically always unproblematic, because no user expects an exact, instant number and a briefly incorrect value causes no real damage.
For account balances, inventory with scarce availability, access permissions, or anything with a legal proof requirement, eventual consistency is instead generally unacceptable, because a stale view of this data can lead to double sales, unauthorized access, or incorrect bookings. The rule of thumb: the higher the cost of a briefly incorrect answer, the more the use case needs strong consistency instead of eventual consistency, even if that means more latency or lower availability.
7. Measuring and monitoring replication lag
A system with eventual consistency without active monitoring of replication lag is a blind system: nobody knows how stale the data on a particular replica actually currently is. PostgreSQL offers the system view pg_stat_replication on the primary for this, which shows the lag of every connected replica in bytes and, via additional functions, in seconds.
# Query replication lag in PostgreSQL directly on the primary
psql -d shop -c "
SELECT client_addr, state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
replay_lag
FROM pg_stat_replication;
"
# Example output:
# client_addr | state | lag_bytes | replay_lag
# --------------+-----------+-----------+-------------
# 10.0.1.12 | streaming | 8192 | 00:00:00.42
# 10.0.1.13 | streaming | 245760 | 00:00:03.91
# A lag of under a second is unproblematic for most use cases,
# several seconds of lag should actively trigger an alert
For production operation, this value should be continuously monitored and equipped with alerting that triggers once the lag exceeds a threshold defined for the respective use case. Without this monitoring, eventual consistency problems are often only noticed once users complain about inconsistent data, which is significantly later and more expensive than a proactive alert.
#!/usr/bin/env bash
set -euo pipefail
# Simple monitoring script: checks replication lag and alerts
# when a defined threshold is exceeded
THRESHOLD_SECONDS=5
lag=$(psql -d shop -t -c \
"SELECT EXTRACT(EPOCH FROM replay_lag)::int FROM pg_stat_replication LIMIT 1;")
if [[ -z "$lag" ]]; then
echo "[WARN] No replica connected or lag not measurable"
exit 1
fi
if (( lag > THRESHOLD_SECONDS )); then
echo "[ALERT] Replication lag ${lag}s exceeds threshold of ${THRESHOLD_SECONDS}s"
exit 2
fi
echo "[OK] Replication lag: ${lag}s"
8. Eventual consistency with read replicas in SQL databases
A common misunderstanding is associating eventual consistency exclusively with NoSQL systems. In reality, every relational database with asynchronous read replicas introduces the same guarantee: write operations run on the primary, are replicated asynchronously to replicas, and a read operation on a replica can briefly return an older state than the primary already has. PostgreSQL, MySQL, and most cloud database services offer this mode by default, because synchronous replication costs latency on every write operation.
The practical handling of this differs little from a native NoSQL solution: critical reads immediately after a write should be explicitly directed against the primary, while non critical reports and analytics queries can comfortably be served by replicas. Whoever makes this distinction deliberately uses the scaling advantages of read replicas without being surprised by unexpected eventual consistency effects.
9. Consistency models in direct comparison
The following table compares the most important consistency models between strong and eventual consistency.
| Model | Guarantee | Typical use case |
|---|---|---|
| Strong consistency | Always the most current value, regardless of node | Account balances, payments, access rights |
| Bounded staleness | Staleness limited to a defined time or version | Dashboards with a guaranteed maximum delay |
| Read your writes | Own changes visible immediately | Profile editing, comments, user settings |
| Eventual consistency | Convergence guaranteed, no time point promised | Like counters, recommendations, activity feeds |
No model is inherently superior, each solves a different trade off between correctness, latency, and availability. The right choice always results from the concrete consequences that a briefly stale view of the data actually has for the respective use case.
10. Summary
Eventual consistency is a deliberate, technically precisely defined consistency guarantee that follows from the CAP theorem and enables availability as well as low latency at the cost of temporarily differing views on the same record. The spectrum between strong and eventual consistency includes practical intermediate stages like bounded staleness and read your writes, which solve many real problems without giving up the full availability advantages of a distributed system.
Conflict resolution with last write wins, vector clocks, or CRDTs determines how conflicting versions get merged back together, while active monitoring of replication lag prevents eventual consistency problems from staying unnoticed until users complain. What always remains decisive is the concrete consequence of a brief discrepancy: where it is harmless, the higher availability of eventual consistency pays off, where it causes real damage, strong consistency remains non negotiable.
Understanding eventual consistency in practice, the essentials at a glance
CAP theorem
During a network partition, a distributed system must choose between consistency and availability.
Intermediate stages
Read your writes and bounded staleness solve most practical problems without needing strong consistency.
Conflict resolution
Last write wins is simple but risky. Vector clocks and CRDTs resolve conflicts more precisely and sometimes automatically.
Monitoring
Replication lag must be actively measured and alerted on, otherwise consistency problems stay unnoticed.