Skip to content
advanced Phase 7 · Consistency, Replication, and CAP Trade-offs

CAP and PACELC Trade-offs

Frame partition-time choices between consistency and availability explicitly.

50m
0 problems
Topic Progress 0%

During the Outage: What a CP System and an AP System Actually Do

At 02:14 the switch between your two availability zones drops half the traffic for eleven minutes. Nothing else is wrong — every process runs, every disk is healthy. During those eleven minutes, what does your key-value store return: a value, or an error? CAP says you must decide now, because during a partition consistency (every read sees the latest completed write) and availability (every non-failing node answers) cannot both be held.

The argument is small enough to derive in an interview:

Client C writes x=1 to node N1. The N1↔N2 link is partitioned.
N2 still receives reads. Two choices for N2's answer to read(x):

  answer x=0 (stale)  → AP: available, but C's completed write is invisible
                         ⇒ not linearizable consistency
  refuse/error        → C: consistent with x=1, but N2 did not serve
                         ⇒ not availability
There is no third answer: N2 cannot learn the new value because
the very link that would carry it is the one that is broken.

Real systems place themselves deliberately on this line:

During a partition Behavior Examples
CP minority side refuses writes; reads served only with proof of freshness (quorum/leader lease). The minority is effectively down etcd, ZooKeeper, Kafka with acks=all under min-ISR loss, Postgres synchronous quorum losing a node
AP every node answers, accepting divergence; conflicts resolved at merge time Cassandra (default QUORUM degrades to local replies), Dynamo-style stores, Riak, CouchDB

Two clarifications interviewers probe for. First, CP often means 'partial unavailability by design' — ZooKeeper's minority serving no writes is the correct, safety-preserving answer, not a bug; and a system can be CP for some operations and AP for others (Kafka is CP for producer acks with acks=all and min-ISR unmet, but consumers reading from an out-of-date replica are being served stale data on purpose). Second, availability in CAP is defined narrowly: a node that responds to every request with HTTP 503 is available by liveness but useless to you; the formal definition means a non-failing node returns a response — so CAP's 'A' is about responding, not about responding usefully, which is why the debate gets muddled.

Also worth saying: partitions are not hypothetical and not only cable cuts. A GC pause of 800 ms, a full disk queue, a confused load balancer, or an asymmetric routing failure all present as partitions to the protocols — timeouts are how a partition is detected, and every partition-time decision is therefore a decision you make under uncertainty about whether the other side is dead or just slow. That uncertainty is exactly what consensus resolves with terms and majorities (Consensus Overview with Raft), and what replication mode determines in the first place (Replication Fundamentals).

The practical move: do not pick a side for the whole database. Classify operations. reserveSeat(seatId) must refuse on the minority side (C) or you oversell; recordPageView must keep accepting (A) or the analytics pipeline stops for eleven minutes for no benefit. Most mature systems expose this per operation: Kafka's acks and enable.idempotence, Cassandra's per-query CONSISTENCY, DynamoDB's on-demand vs strongly consistent reads. Answering with a per-operation classification is how you pass this question.

The Other 99.99% of the Time: PACELC Prices the Normal Case

Your cluster ran for a year with 4 minutes of partition. For the other 525,596 minutes, CAP had nothing to say — yet you still chose synchronous replication over asynchronous, quorum reads over local reads, writeConcern=majority over writeConcern=1. Those choices trade latency for consistency while everything is healthy, and CAP does not model them at all. PACELC (Abadi, 2012) adds the missing half: if there is a Partition, choose between Availability and Consistency; Else, choose between Latency and Consistency.

That framing produces four labeled quadrants, which is why it is more useful than a CP/AP badge:

                 partitioned          healthy
        ┌──────────────────────┬──────────────────────┐
 choose │  P-A : Cassandra,    │  E-L : DynamoDB default,
        │  DynamoDB on-demand, │      MongoDB w:1 j:false,
        │  Riak               │      Cassandra LOCAL_ONE
        ├──────────────────────┼──────────────────────┤
        │  P-C : ZooKeeper,    │  E-C : Spanner,
        │  etcd, Kafka acks=all│      Postgres sync-commit,
        │  (minority refuses)  │      MongoDB w:majority
        └──────────────────────┴──────────────────────┘

Reading the bottom-right row is the point: Spanner and a w=majority Postgres are both E-C — they pay RTT on every operation during normal operation, which is why cross-region synchronous replication shows up as p99 latency before it ever shows up as an outage. The top-left row prices the opposite call: Cassandra tuned for LOCAL_ONE accepts staleness in the healthy case (E-L) and accepts divergence during partitions (P-A) — one tuning philosophy expressed in two regimes.

Concrete numbers make this interviewable:

Configuration Healthy-case cost Partition-time behavior
acks=all, min.insync.replicas=2, cross-AZ +1 AZ round trip (~0.5–2 ms) on produce loses availability if 2 of 3 brokers die; no data loss
acks=all, cross-region ISR +50–200 ms per produce region outage blocks writes
acks=1 local broker only (~1 ms) leader death can lose unflushed batches — the AP-leaning choice
Mongo w:1, j:false fastest ack; journal not fsynced primary death can lose acknowledged writes
Mongo w:majority, j:true every write waits for majority + fsync minority partition cannot accept writes

The design discipline PACELC forces: write down both answers. A system description that says only 'we are AP' tells you nothing about whether it adds 1 ms or 150 ms to your write path in production — and the E-C/E-L decision is the one your users feel every day, while the P-C/P-A decision is the one your incident review feels once a year.

A useful exercise is to score your own service on all four cells. Take an order API: with writeConcern=majority on the primary and reads at readConcern=linearizable for checkout, it is E-C; if the primary's region is cut off, orders stop — P-C. Now the recommendation feed: reads at readConcern=available from secondaries and writes acked at w:1 — E-L for both halves, so a partition means some users see older suggestions for a while. Two collections inside one cluster, two PACELC answers, one per operation rather than one per vendor. Write the table down in the design doc; it turns arguments about 'strong vs eventual' into a list of settings someone can review and change.

One trap: PACELC still treats the system as one point, and real deployments are per-operation hybrids — Kafka is E-C for producers with acks=all and E-L for consumers reading followers; MongoDB can be w:majority for the ledger and w:1 for the session store in the same process. The labels are a starting vocabulary, not the conclusion; the next chapter is about why the conclusion needs a scenario attached.

Why 'Our Database Is CP' Is an Incomplete Answer, and What to Say Instead

Ask three engineers whether their system is CP or AP and you will get three answers, all defensible — because the label is meaningless until you name which partition you are talking about. CAP constrains behavior only for the specific partitioned scenario assumed, and systems have several:

  • One node is isolated from its peers (the classic majority/minority split). ZooKeeper is CP here: the minority refuses writes.
  • One node is isolated from the clients but connected to peers. Now that node serves nothing while the cluster is perfectly consistent and available — no C/A choice was made at all.
  • A client is partitioned from part of the cluster (a load balancer or firewall fault). Reads from stale replicas may be served while the cluster itself is healthy — AP-looking behavior from a CP system.
  • A node is slow, not dead — a 700 ms GC pause. Protocols must treat it as a partition (timeouts cannot distinguish), so the choice happens even though the network is fine.

Say that list in an interview and the question changes shape: instead of 'we are CP', the senior answer is 'when node-to-node links partition, our primary and secondary coordination tier fails closed — minority refuses writes — while our read path degrades to stale-but-serving after the lease expires, so per operation we are CP for writes and AP for reads.' That sentence contains verifiable behavior; a badge does not.

The framework that produces it:

For each operation:
 1. Name the invariant it protects.        (no double-sell, no lost transfer,
                                             page views may drop)
 2. Name the partition scenario assumed.    (who can be cut off from whom,
                                             and for how long before failover)
 3. State the answer for both sides.        (minority refuses / minority serves stale,
                                             with the reconciliation path named)
 4. State the healthy-case latency budget.  (the E half of PACELC)
 5. Name the reconciliation mechanism.      (repair, anti-entropy, saga, leader election)

Step 5 is the part most candidates skip, and it is what makes an AP choice responsible rather than careless: an AP system is not 'eventually fine', it is 'divergent and equipped with a merge function, versioning, and a repair path' (Consistency Models covers those mechanisms). A CP system's counterpart is an election and fencing story. Every CAP answer is really a pair: a refusal policy and a reconciliation policy. Walk a real example through the five steps and the framework shows its value: a shopping cart stored with per-write versioning, AP during a partition because abandoned carts tolerate merged items, reconciled by union-with-tombstones on healing — while the inventory reservation in the same request path is CP, refusing reservations on the minority side and reconciling through the saga's compensating release. Same outage, opposite answers, both correct.

A final practical note: CAP-shaped decisions are usually made by a handful of configuration values you can point at — min.insync.replicas, writeConcern, ConsistencyLevel, lease TTLs, and timeout thresholds — so an architecture review can audit them. Ask which of those settings implements the claimed badge; if nobody can name one, the label is folklore. Those same timeout and quorum parameters decide how your system behaves when messages pile up, which is where the roadmap goes next: Message Queues and Brokers.

Quiz

1. During an AZ partition, a client's write to x=1 completed on N1. N2 is isolated from N1 but still serving clients. What can N2 do?

Question 1 options

2. Your cluster had zero partitions this year, yet you chose w:majority + journal:true for every write. Which PACELC quadrant does that represent, and what did you pay?

Question 2 options

3. A colleague says 'we are AP because Cassandra is AP.' What is the strongest rebuttal?

Question 3 options

4. A 900 ms GC pause on a database node causes clients to time out and a failover to trigger. How does this relate to CAP?

Question 4 options

Flashcards

Question

State CAP precisely, including what it does and does not say about normal operation

Answer

During a network partition, a system cannot simultaneously guarantee consistency (every read sees the latest completed write) and availability (every non-failing node responds); it must choose per the scenario. CAP says nothing about the healthy case — latency-versus-consistency trades there are PACELC's territory, which is why 'we are CP' does not describe your day-to-day latency.

Question

What does PACELC stand for, and what does it add that CAP cannot?

Answer

If Partitioned, choose Availability vs Consistency; Else choose Latency vs Consistency. It prices the normal case, where CAP is silent: synchronous quorum replication is EC (consistent, slower even with no outage), Cassandra with LOCAL_ONE is EL, ZooKeeper is PC, and DynamoDB on-demand is PA — giving four quadrants instead of one badge.

Question

Why is 'is it CP or AP?' an incomplete question?

Answer

Because CAP applies only under the specific partition assumed: a peer-isolated node, a client-isolated node, and a client cut off from one replica produce different C/A answers for the same system. The complete answer names the scenario (who is cut from whom), the behavior per operation, the healthy-case latency budget, and the reconciliation path after healing.

Question

Compare Kafka acks=all with min.insync.replicas=2 versus acks=1 in both PACELC regimes

Answer

acks=all + min ISR 2: EC healthy (each produce waits for an AZ round trip, no data loss on broker death) and CP partitioned (producers block when the ISR shrinks below 2). acks=1: EL healthy (local ack ~1 ms, unflushed batches at risk) and PA-ish partitioned (writes continue on the leader, unreplicated data can be lost on failover).

Question

What two policies must accompany any AP choice to make it responsible?

Answer

A merge/reconciliation policy and a repair path: versioning or CRDT semantics to resolve conflicting writes, plus active mechanisms (read repair, anti-entropy, sagas, human merge queue) that actually drive replicas together. Availability without a defined conflict-resolution story is not an AP design — it is unbounded divergence deferred to the reader.

Revision Notes

Key Takeaways

  • 1. CAP is a decision made under partitions only — refusing writes on the minority side is a designed choice, not an outage, and answering stale is the other designed choice
  • 2. PACELC supplies the missing healthy-case row: your E-C/E-L tuning is what users feel daily, while the P-C/P-A badge is what the postmortem sees yearly
  • 3. Timeouts detect partitions, and slow is indistinguishable from dead — so GC pauses and full disks trigger the CAP decision on healthy networks
  • 4. Real systems are per-operation hybrids: classify each operation against its invariant rather than assigning one badge to a database
  • 5. Every AP answer needs a reconciliation mechanism named alongside it, or it is unbounded divergence rather than a design

Interview Tips

  • • "Explain CAP" — derive it in five lines from one partitioned write, then say CAP constrains only the partitioned regime; the derivation beats the acronym
  • • "Is Redis CP or AP?" — answer with a scenario: master-replica async replication is AP for replica reads (stale allowed), CP-ish for writes during failover; naming the config (WAIT, min-replicas) shows you know where the dial is
  • • "What does PACELC add?" — the Else clause: name the healthy-case latency price of your consistency settings with real numbers (AZ RTT, WAN RTT, fsync)
  • • "Give one operation that must be CP and one that must be AP" — reserve/charge vs telemetry append, each justified by an invariant, then state the reconciliation path for the AP side

Cheat Sheet

CAP / PACELC

CAP derivation (say it, don't quote it): write lands on N1, N1↔N2 partitioned, N2 still gets reads → stale answer = available-but-inconsistent, refusal = consistent-but-unavailable. The broken link is the only channel that could carry the new value.

during partition healthy
C-biased minority refuses writes (ZK, etcd, Kafka acks=all w/ min-ISR) majority quorum + fsync per op: +RTT to p99 (Spanner, sync-commit PG, w:majority)
A-biased every node answers, divergence queued for merge (Cassandra, Riak, Dynamo) local ack, no remote wait (acks=1, w:1 j:false, LOCAL_ONE)

PACELC: If Partitioned → A or C; Else → Latency or Consistency. Name both halves; per-operation hybrids are normal (Kafka: E-C producers, E-L consumers).

Why 'CP/AP' is incomplete: specify the partition (peer-isolated vs client-isolated vs slow-node/GC) — same system answers differently. CAP's A only means 'responds', not 'responds correctly'.

Per-operation answer template:

1. invariant?          reserveSeat → no double-sell · pageView → may drop
2. scenario?           who cut from whom, how long before failover
3. minority side?      refuse (C) or serve stale + reconcile (A)
4. healthy latency?    the E half: +AZ RTT, +WAN RTT, or local ack
5. reconciliation?     election+fencing (C) · merge fn + repair (A)

Audit hooks: min.insync.replicas · writeConcern/journal · CONSISTENCY level · lease TTL · timeouts (a pause looks like a partition).

Continue Learning

Before You Start

Related Reading