CAP, PACELC and consistency models
We'll cover the following
CAP, precisely
- Partition (network failure between nodes) is a given, not a choice. CAP really says: when a partition happens, choose C or A. With a healthy network you can have both. "Pick 2 of 3" oversimplifies.
- CP: refuse or error rather than return a possibly stale answer (payments, inventory).
- AP: always answer, maybe stale (feeds, likes).
- Eventual consistency is not just for read-heavy systems. It is about what staleness you can tolerate.
- Strong: the 200 means the write is on enough replicas (usually a quorum) that any later read sees it. Eventual: the 200 comes after one replica has it and the others catch up.
PACELC (say "pass-elk")
If Partition, choose A or C. Else, choose Latency or Consistency. Even when healthy, waiting for more replicas gives better consistency but slower responses. DynamoDB default reads are fast and eventually consistent; Spanner is consistent but pays in latency.
It is a setting, not a product label
- Postgres with a single primary and sync replicas behaves CP. With async replicas, replica reads are stale (eventual) but writes still stop if the primary dies.
- Distributed SQL (Spanner, CockroachDB) is firmly CP.
- Cassandra with
QUORUMreads and writes acts CP for that query; drop toONEand it is AP. - DynamoDB and Cassandra let you pick per query.
Quorum
Data is copied to N replicas (say 3). W = replicas that must confirm a write, R = replicas you ask on a read. If R + W > N the read and write groups overlap in at least one replica, so a read always touches a node with the latest write. N=3, W=2, R=2 gives strong consistency and still survives one node down. W=1, R=1 is faster but can read stale.
Read-your-own-writes
User changes their profile picture: others may see the old one for a few seconds (eventual is fine), but the user must see the new one immediately. It is a session guarantee. Get it by reading the user own data from the primary for a short window after they write, updating the UI optimistically, or passing a version/timestamp so a lagging replica refuses to serve.
What CP vs AP changes beyond a toggle
- Replication: synchronous (CP-ish) vs asynchronous (fast, AP-ish).
- Quorums: choose R and W.
- Failure behavior: reject during a partition vs keep serving stale.
- Conflict handling (AP): both sides accepted writes, so you need last-write-wins, vector clocks or CRDTs.
- Caching: TTLs and invalidation are consistency decisions. Cache seat availability for display with a short TTL, but never trust the cache for the booking itself; the final check hits the DB in a transaction.
- Multi-region: single leader or active-active (below).
- Cross-service flows: 2PC or sagas (next section).
- UX: optimistic UI, "pending" states, retries and idempotency.
Multi-region: single leader vs active-active
| Single leader | Active-active | |
|---|---|---|
| Writes | All go to one region (e.g. US); far users pay ~200ms | Each region accepts writes locally |
| Pros | One source of truth, no conflicts | Fast everywhere |
| Cons | Slow for distant users | Same record edited in two regions at once means conflicts you must merge |
| Fits | Ticket booking | Collaborative or feed-like data |
Pick consistency per piece, not per system
- A common mistake is answering a CAP question with one word for the whole system: "I pick availability." Real systems are made of many small pieces, and each piece can choose differently.
- The questions to ask: which piece of data must everyone agree on, and how big is that piece? For a chat app, the thing that must agree is the order of messages inside one conversation. It does not need to agree across all conversations in the world.
- So give each conversation a single owner (one server that numbers its messages). That owner is what keeps the order consistent.
- Now the partition case: if that owner is unreachable for a moment (a crash, a failover), that one conversation briefly stops accepting new messages rather than risk two different orders. That is the consistent (CP) choice, but only for that one conversation.
- Every other conversation has its own owner and keeps working, so the system as a whole stays available.
- Say it like this: "I would not pick CP or AP for the whole system. Order has to be consistent per conversation, so a conversation pauses during its owner failover, while every other conversation stays up."
- Details of how the owner numbers messages: see Ordering, acks and delivery guarantees.
Summary: say it in the interview
- "I pick consistency per feature. Payments and inventory are CP with sync replication. Feeds and likes are AP with async replicas, and I add read-your-own-writes for the user own actions."