Be Software Architecture Wise
Be Wise Apps

Leer en español · Lire en français · Auf Deutsch lesen

Section 6.6 of 6.8 · Advanced · 30 min read

Consistency models, CAP and PACELC

Video lesson

5 min · narrated, with captions
Listen only (audio)
Read the transcript

Once data is copied, the copies can disagree. In this lesson you'll learn the main consistency models, what the CAP theorem really says, the everyday trade-off that PACELC adds, and how to choose.

Imagine a shop with three branches. Each keeps a copy of the stock list, and they phone each other with updates. If the line goes down and a customer asks one branch for the last bicycle, it can say, I can't be sure, please wait. Or it can answer from its own list, and risk selling a bike another branch has just sold. Even when the phones work, checking with the others first makes customers wait. Distributed systems face exactly these choices, and the right one depends on what a wrong answer would cost.

A consistency model is the contract that says which disagreements between copies clients may observe. Beware the overloaded word. The C in ACID means moving from one valid state to another. In CAP, which stands for consistency, availability and partition tolerance, the C is narrower: every read behaves as if there were a single, up-to-date copy.

Here's the ladder, from strongest to weakest. Linearisable behaves as if there were one copy: once a write completes, every later read sees it. If two customers claim the last discount code, exactly one succeeds. Sequential keeps one agreed order of writes, but a read may be slightly out of date. Causal only requires that causes are seen before effects. A restaurant's answer in the order chat must never appear without the customer's question. Session guarantees are promises to one client. After you change your address, you see the new one. And once you've seen out for delivery, you never see preparing again. Eventual is the weakest useful guarantee: if writes stop, all replicas eventually agree. It doesn't say how long that takes. Each step down means less coordination and lower latency, and the weaker models keep working during a network partition.

Now the CAP theorem, using a ticketing system. Client one buys seat fourteen C through replica A, which records it as sold. Then a network partition cuts replica A off from replica B, so B can't learn about the sale. Client two asks replica B whether seat fourteen C is free. B must choose. It can choose consistency: refuse or time out, and say try again later. Or it can choose availability: answer that the seat is free. That's stale, and the seat may be sold twice.

Pick any two of three is a misreading. In any networked system, partitions happen whether you choose them or not. The only choice is how to behave when they do. Partitions are rare, so most of the time a system can offer both. The choice applies only during a partition, and can differ for each operation. So design for partitions: detect them, limit some operations, such as accepting orders but postponing refunds, and afterwards merge state and compensate for mistakes. PACELC adds what CAP leaves out. If there's a partition, choose availability or consistency. Else, in normal operation, choose latency or consistency, because consistent reads need coordination, and you pay for it on every request.

Some stores let you tune this with arithmetic. With N replicas, a write is acknowledged once W have stored it, and a read asks R replicas and takes the newest version. Here N is three, and W and R are both two. The writer sets a price of twelve, and replicas one and two acknowledge it. Replica three is lagging, still holding ten. The reader collects replies from two replicas: the lagging replica three, and replica two. Because R plus W is greater than N, the two sets must overlap. Here, replica two is in both. So the reader sees the newer version, and returns twelve. But overlap alone isn't linearisable. For example, clocks that disagree can make a later write lose. So the platform also charges customers the price stored in the order at checkout.

So ask, for each piece of data, what goes wrong if a client sees a stale value, and what it costs. Money, the last seat at an on-sale and a unique username justify strong consistency. A customer's own address and order status need only session guarantees, which are cheap: for example, read from the leader for a few seconds after that user writes. A restaurant chat needs causal order. And likes, ratings and a courier's dot on the map can be eventual. But eventual consistency is visible to users, so it needs product decisions, not just technical ones.

The full section works through the quorum choices, and shows how four well-known databases can be configured. Next, in Section six point seven, we look at sagas and distributed transactions. See you there.

What you need to know

What "consistent" means once data is copied

As soon as a system keeps more than one copy of a piece of data, on replicas in different zones, in caches or in other services, the copies can disagree for a while. A consistency model is the contract that says which disagreements clients may observe. It is a promise about what reads can return given the writes that have happened, and therefore a promise about which surprises application code must handle.

Beware the overloaded word. The C in ACID (Section 0.5) means a transaction moves the database from one valid state to another, respecting rules such as "a balance never goes below zero". The C in CAP means something different and narrower: every read behaves as if there were a single, up-to-date copy. Database isolation levels such as serialisable or read committed are a third family, about concurrent transactions; they are covered in transactions and isolation. This section is about the guarantees of replicated data.

Consistency models from strongest to weakest

Linearisability, defined by Maurice Herlihy and Jeannette Wing in 1990, is the strongest single-object model. Every operation appears to take effect instantaneously at some point between its start and its end, and all clients see the same order, which respects real time: once a write has completed, every read that starts afterwards sees it or something newer. The system behaves as though there were one copy. Food-delivery example: two customers try to claim the last discount code; with a linearisable store, exactly one succeeds and the other sees it gone, whichever replica they reach.

Sequential consistency, defined by Leslie Lamport in 1979 for multiprocessors, keeps the single global order and keeps each client's operations in the order that client issued them, but drops the real-time requirement. A client may read a value that is slightly out of date, as long as everyone agrees on the order of all writes. It is rarely offered by name in distributed databases but explains the gap between "one agreed order" and "one agreed order that matches the clock".

Causal consistency requires only that operations which are causally related are seen in the same order by everyone: if writing B depended on having seen A, nobody may see B without A. Concurrent, unrelated writes may be seen in different orders by different clients. Example: a restaurant replies "Yes, it is gluten-free" to a customer's question in the order chat; nobody should ever see the answer without the question. Causal consistency is attractive because Jepsen's widely used map of consistency models classifies it as achievable with sticky availability: it can keep working during a partition as long as each client stays with the same replica.

The session guarantees, described by Douglas Terry and colleagues in 1994, are weaker, per-client promises that remove the most confusing anomalies. Read-your-writes: after a customer changes the delivery address, that customer's next read shows the new address, even if other users see it later. Monotonic reads: once a client has seen the order status "out for delivery", it never later sees "preparing" because a later read hit a lagging replica. (Two further guarantees, monotonic writes and writes-follow-reads, constrain the order in which a client's writes are applied.)

Eventual consistency, popularised by Werner Vogels in 2008, is the weakest useful guarantee: if no new writes arrive, all replicas eventually converge on the same value. It says nothing about how long that takes or what may be read in the meantime, and a basic implementation that resolves conflicting writes by keeping the one with the latest timestamp, known as last write wins, silently discards the other. Stronger forms, such as strong eventual consistency with conflict-free replicated data types (CRDTs), guarantee that replicas which have received the same updates hold the same state, by using data types whose concurrent updates always merge, such as counters and sets.

The consistency ladder

A ladder of consistency models from linearisable at the top to eventual at the bottom, with the cost of coordination falling as guarantees weakenLinearisableone copy, real-time orderSequentialone order, per-client program orderCausalcauses seen before effectsSession guaranteesread-your-writes, monotonic readsEventualreplicas converge if writes stopStrongerWeakereasier toreason aboutmore coordinationhigher latencyunavailable ina partitionless coordinationlower latencyavailable ina partition
Each step down removes a guarantee and some coordination; the session guarantees are per-client promises that sit between causal and plain eventual consistency.

CAP: what it actually says

Eric Brewer presented the CAP idea as a conjecture in his keynote at the ACM Symposium on Principles of Distributed Computing (PODC) in 2000. In 2002 Seth Gilbert and Nancy Lynch published a formal proof, making it a theorem for their precise definitions. Consistency meant linearisability. Availability meant that every request received by a node that has not failed must result in a response. Partition tolerance meant the system keeps its promises even when the network loses arbitrarily many messages between nodes.

Read carefully, the CAP theorem is narrow. It says that when a network partition occurs, so that some nodes cannot reach others, a replicated system must choose for each request between consistency and availability. A node cut off from the latest writes can either refuse to answer (or wait until the partition heals), preserving consistency, or answer with what it has, preserving availability at the risk of returning stale data or accepting conflicting writes. The diagram shows the dilemma for a ticketing system selling seat 14C.

Several popular readings are wrong. "Pick any two of three" suggests partition tolerance is optional, but in any system that communicates over a network, partitions happen whether or not you choose them; the only real choice is how to behave when they do. A so-called "CA" system is one that has not decided what to do when a partition occurs; that is defensible only where partitions are practically impossible, such as on a single node. "Our database is CP (or AP)" is usually imprecise: CAP availability is a very strong property that many systems marketed as highly available do not have, and many systems called CP are not linearisable either. Martin Kleppmann argued in 2015 that databases should not be labelled CP or AP at all, because most fit neither definition and their behaviour depends on configuration. "CAP explains our latency" is also wrong: CAP says nothing about what happens when there is no partition, which is most of the time.

The CAP choice, made concrete

During a network partition, replica B must either refuse to answer or answer with possibly stale dataClient 1Client 2Replica Aseat 14C: soldReplica Bseat 14C: freebuys 14Cis 14C free?partitionChoose consistency (CP)B refuses or times out:"try again later"Choose availability (AP)B answers "free":stale; seat may be sold twiceB must choose
Replica B cannot learn that seat 14C has just been sold on replica A, so it must either refuse to answer or risk selling the seat twice.

CAP twelve years later

In 2012, in an IEEE Computer article titled "CAP Twelve Years Later: How the Rules Have Changed", Brewer himself explained that the two-of-three framing had misled people. Partitions are rare, so a system can offer both consistency and availability almost all of the time; the choice applies only during a partition, and only to the operations affected. The choice need not be global either: different operations and different data can make different choices.

Brewer recommended designing explicitly for partitions in three steps: detect the partition, enter an explicit partition mode in which some operations are limited (for example, accept orders but postpone refunds), and run a recovery process afterwards that merges state and compensates for mistakes made during the partition. He also noted that CAP's C is single-copy consistency, a stricter subset of what ACID's C protects, and that invariants such as "never oversell" may have to be repaired after the fact. This framing leads directly to the business-level compensations of sagas: an airline that oversells a flight compensates the passenger rather than refusing all bookings during a network fault.

PACELC: the trade-off you pay every day

Daniel Abadi pointed out in a 2010 blog post, and in a 2012 IEEE Computer article, "Consistency Tradeoffs in Modern Distributed Database System Design: CAP is Only Part of the Story", that CAP ignores the trade-off designers actually face most of the time. PACELC reads: if there is a Partition, choose between Availability and Consistency; Else, in normal operation, choose between Latency and Consistency.

The "else" half is the important addition. To make a read consistent, a replicated system must coordinate: send the write to other replicas and wait for acknowledgements, or route every read to a leader, or contact several replicas and compare. Every one of those costs network round trips, and across regions a round trip can cost tens or even hundreds of milliseconds. A system that answers from the nearest replica without coordinating is faster but may be stale. That trade-off is paid on every request, partition or not.

PACELC classifications are often quoted, such as PA/EL for systems tuned for speed and availability and PC/EC for systems that always prefer consistency. Treat them as descriptions of a configuration, not of a product: the same database can be PA/EL in one deployment and PC/EC in another, depending on settings chosen per table, per query or per request.

Quorums: tuning consistency with arithmetic

Leaderless replicated stores, in the style of Amazon's Dynamo paper (2007), let each operation choose how many replicas to involve. With N replicas of an item, a write is acknowledged when W replicas have stored it, and a read collects answers from R replicas and returns the newest version among them. If R + W > N, every read set overlaps every write set in at least one replica, so a read will include at least one copy of the latest acknowledged write.

The choice of R and W trades consistency, latency and availability. Lower values mean waiting for fewer, faster replicas and tolerating more failures, at the price of possible stale reads. Higher values mean the opposite. Writes are usually sent to all N replicas anyway; W only decides how many acknowledgements the client waits for.

Quorum overlap is necessary for fresh reads, but it is not, on its own, linearisability. Concurrent writes may be ordered by timestamps from clocks that disagree, so a later write can lose under last-write-wins. A write that failed after reaching some replicas may still be visible on them. "Sloppy" quorums, which accept writes on substitute nodes during failures, break the overlap. And two reads that overlap a write still in progress can see new then old values unless the reader repairs lagging replicas before returning. Stores that need true compare-and-set semantics add a consensus protocol, such as the Paxos-based lightweight transactions in Apache Cassandra, for those operations only.

Why R + W > N works

With three replicas, a write acknowledged by two and a read from two must overlap in at least one replicaN = 3 replicas, W = 2, R = 2Writerprice = 12ReaderReplica 1v2: 12Replica 2v2: 12Replica 3v1: 10 (lagging)W = 2 acksR = 2 repliesReplica 2 is in both sets:the reader sees v2 and returns 12
The write was acknowledged by replicas 1 and 2; the read asks replicas 2 and 3; the overlap at replica 2 means the newest version is in the read set.

Worked example

Worked example: choosing N, W and R for a menu-price store

The food-delivery platform stores menu prices in a leaderless store with N = 3 replicas, one per availability zone. Each replica answers in about 2 ms within its zone and about 5 ms from another zone. The quorum client waits for the W-th (or R-th) fastest reply.

W = 2, R = 2 (R + W = 4 > 3)Overlap guaranteed. Reads and writes each wait for the second-fastest replica (about 5 ms). Both still succeed with one zone down. A common balanced default.
W = 3, R = 1 (4 > 3)Overlap guaranteed and reads are fast (nearest replica, about 2 ms), but every write fails if any one replica is down: write availability is the product of three availabilities. Suits data written rarely and read constantly, if write failures can be retried later.
W = 1, R = 3 (4 > 3)Writes are fast and survive two failures; every read must reach all three replicas, so reads fail if any zone is unreachable. Rarely a good trade.
W = 1, R = 1 (2, not > 3)Fastest and most available, but a read can miss the latest write entirely. Acceptable for a popularity counter; not for a price the customer will be charged.
N = 5, W = 3, R = 3 (6 > 5)Overlap guaranteed while tolerating two failed replicas for both reads and writes, at the cost of more storage and slightly slower quorums.

General rule: with R + W > N, writes tolerate N − W failures and reads tolerate N − R failures.

Overlap gives fresh reads only for acknowledged writes and only with reliable versioning; see the caveats above before relying on quorums for invariants such as stock levels.

For prices, the platform chose W = 2, R = 2, and charged customers using the price stored in the order at checkout, so a stale menu read could never change what was charged.

How well-known databases can be configured

Real products rarely sit at a single point on the ladder. They expose settings, and the right description is "how this deployment is configured". Four common examples follow; check the current documentation of the version you run, because defaults change between releases.

Configurable consistency in four widely used databases (behaviour as documented at the time of writing)

DatabaseTypical default behaviourSettings that strengthen consistencyWhat to watch
PostgreSQL with streaming replicationOne primary takes all writes; replication to standbys is asynchronous by default, so reads from a standby may be stale.synchronous_standby_names with synchronous_commit (for example remote_apply) makes a commit wait until standbys have it; read from the primary for read-your-writes.Synchronous replication adds commit latency, and writes stall if the required standbys are unreachable.
MongoDB replica setWrites default to majority acknowledgement in most deployments; reads from the primary default to read concern local, which can return data later rolled back.Read concern majority or linearizable; causally consistent sessions when both reads and writes use majority.Reading from secondaries (read preference) trades freshness for latency and load.
Apache CassandraConsistency level is chosen per request (ONE, QUORUM, LOCAL_QUORUM, ALL and others); conflicts resolve by last-write-wins timestamps.QUORUM (or LOCAL_QUORUM within a data centre) for both reads and writes so that R + W > replication factor; lightweight transactions for compare-and-set.Clock skew affects last-write-wins; LOCAL_QUORUM gives no cross-data-centre guarantee.
Amazon DynamoDBReads are eventually consistent by default; global tables replicate between regions asynchronously by default.ConsistentRead=true on tables and local secondary indexes; global tables with multi-Region strong consistency (generally available since 2025).Strongly consistent reads are not available on global secondary indexes, consume twice the read capacity and can be slower.

Choosing consistency per use case

The most useful habit is to stop asking "is our system consistent?" and ask, for each piece of data and each operation, what goes wrong if a client sees a stale or reordered value, and how much does it cost? Money moving, unique resources and invariants usually justify strong consistency and its latency. Counters, feeds, recommendations and analytics usually do not. Many user-facing anomalies disappear with just the session guarantees, which are cheap: route a user's reads to the primary for a few seconds after that user writes, or carry a version token in the session and wait until the replica has caught up with it.

Consistency needs by use case

Use caseCost of a stale or reordered readSensible guaranteeTypical mechanism
Bank balance before a withdrawalOverdraft beyond the limit; money lostLinearisable (and serialisable transactions)Single leader for the account, synchronous replication, or consensus
Last seat or ticket at an on-saleSelling one seat twice; refunds and angry customersLinearisable per seatConditional write (compare-and-set) on the seat record
Unique username at sign-upTwo accounts with the same nameLinearisable on the uniqueness checkUnique constraint in one database, or a consensus-backed registry
Customer's own delivery address after editingFood sent to the old addressRead-your-writesRead from the leader after a write, or a session version token
Order status shown to the customerStatus appears to go backwards; confusion and support callsMonotonic reads plus read-your-writesSticky routing to one replica, or version tokens
Restaurant chat with the customerAn answer appears before its questionCausalCausally consistent store, or per-conversation ordering
Shopping basketA removed item reappears; mildly annoyingEventual, with mergeAlways accept adds; merge versions (the Dynamo paper's example)
Likes count or restaurant ratingCount is off by a few for a few secondsEventualAsynchronous replication, counters or CRDTs
Courier location on the mapDot a few seconds behindEventual, latest value winsLow-latency writes to the nearest replica; old positions discarded

Check your understanding

What is the difference between linearisability and sequential consistency?

Both require a single order of operations that all clients agree on and that respects each client's own order; linearisability also requires that order to respect real time, so a read that starts after a write completes must see it.

Why is a "CA" distributed database not a meaningful choice?

Because network partitions happen in any system that communicates over a network; a system that assumes they never occur has simply not decided what it will do when they do.

With N = 5 and W = 2, what is the smallest R that guarantees read and write sets overlap?

R = 4, because R + W must exceed 5.

A user edits their profile and the page reloads showing the old version, although other users seeing it late does not matter. Which guarantee is missing, and what is a cheap fix?

Read-your-writes; route that user's reads to the leader for a short time after a write, or carry a version token and wait for a replica that has caught up.

Next · 6.7SagasHow to keep data consistent when one business action spans several services: two-phase commit and why it is avoided, sagas with compensations, choreography and orchestration, isolation countermeasures, the transactional outbox and idempotent receivers.Continue →

Sources and further reading

Have a question about this section? ArchitectBot, the course’s AI study assistant, answers from the course first.

Ask: “We are adding read replicas to our order database. Which screens in the customer app need read-your-writes, and how do we provide it cheaply?”