Chapter 03 · CAP, PACELC, and Consistency/Availability Tradeoffs
Why CAP Does Not Mean Pick Two During Normal Operation
Deconstruct CAP folklore by separating healthy operation, partitioned operation, ACID consistency, and per-operation degraded modes.
Learning outcomes
After Lesson 1, AtlasMart’s architecture review contains a dangerous sentence: “inventory is CP, catalog is AP, so we already picked two.” That sentence compresses too much. Healthy networks allow many systems to answer requests both consistently and successfully; partitioned networks trigger the theorem’s dilemma; and one system can expose different semantics for different operations. This lesson replaces classification slogans with a state-and-operation view.
Explain exactly why “pick any two of C, A, P” is an inaccurate operational rule.
Separate healthy-network behavior from partition behavior and describe how the same service can change its response mode.
Distinguish CAP consistency from ACID consistency and from replica convergence.
Reason per operation instead of assigning one permanent CAP label to an entire product.
Use AtlasMart invariants to justify degraded modes during a partition.
1. Why the triangle picture causes trouble
The famous triangle invites a static product-classification question: “Which two does this database choose?” The formal result is conditional. When the network prevents replicas from communicating, a service cannot guarantee both linearizable consistency and availability for all requests. When there is no partition, that impossibility does not force a tradeoff between those two properties. A leader can answer quickly, replicas can be synchronized, and requests can succeed.
Replace “is this database AP or CP?” with “for this operation, in this topology, under this failure, what does the client observe and which guarantee is intentionally relaxed?”
2. Normal operation and partitioned operation are different states
| Network state | Inventory reservation | Catalog browse | Why |
|---|---|---|---|
| Healthy | coordinate/conditional write; succeed | serve current replica; succeed | required nodes can communicate |
| Partition | minority/unauthorized side refuses | serve a possibly stale local copy | inventory forbids oversell; catalog tolerates bounded staleness |
| Healing | reconcile metadata and resume normal routing | catch replicas/indexes up | recovery is an explicit phase, not instantaneous magic |
This table does not imply that catalog reads are “AP forever” or that inventory is “CP forever.” It says AtlasMart has two different business contracts. A healthy system may meet both contracts simultaneously. Under failure, each contract specifies its own degraded behavior.
3. CAP C and ACID C are different ideas
Atomicity, Consistency, Isolation, Durability (ACID) describes transaction properties. Its “consistency” means a transaction moves the database from one state satisfying declared integrity rules to another such state, assuming those rules and transactions are correctly designed. CAP’s “consistency” is about the visibility/order of operations across replicas in the theorem’s model. A system can have ACID transactions on one node yet return stale replicated reads elsewhere; conversely, a linearizable register can expose a single ordered value without implementing general multi-row ACID transactions.
| Phrase | Question it answers |
|---|---|
| CAP/linearizable consistency | Can clients reason as if there were one up-to-date copy respecting real-time order? |
| ACID consistency | Do transactions preserve declared invariants/constraints? |
| Eventual convergence | If writes stop and communication resumes, do replicas approach the same state? |
| Durability | After success, what failure classes can the committed result survive? |
4. Per-operation semantics beat product labels
AtlasMart’s same data platform might expose a local stale-tolerant product lookup, a quorum/leader-coordinated inventory mutation, and a write-any telemetry append. The relevant design surface includes request routing, read/write consistency settings, session guarantees, region ownership, and conflict policy. Saying “the database is AP” can hide that one endpoint is deliberately unavailable on an isolated side while another remains useful.
GET /catalog/sku-42
partitioned region: serve local version, include freshness age
POST /inventory/sku-42/reservations
partitioned non-owner region: 503 cannot establish reservation authority
POST /telemetry/click
partitioned region: accept event with idempotency key; reconcile later
5. Deliberately wrong approach — configure from the label
Suppose an engineer writes “we chose AP because checkout must stay online” and therefore permits every region to reserve the last unit independently. The availability goal is real, but the chosen mechanism ignores the inventory invariant. Another engineer writes “we chose CP” and therefore sends every catalog browse across an ocean to the leader, adding latency for a path whose users would tolerate a few seconds of staleness. Both decisions are cargo-cult CAP: they optimize a label rather than the operation.
The repair is to write failure contracts per operation: what can be stale, what may be rejected, what may be queued, what can be compensated, and what must remain single-owner. Those contracts later become tests and SLOs.
6. AtlasMart lab — same system, different operations
from dataclasses import dataclass
@dataclass(frozen=True)
class Operation:
name: str
invariant: str
partition_policy: str
ops = [
Operation("browse catalog", "stale price tolerated briefly", "serve local replica"),
Operation("reserve last unit", "stock must not go below zero", "refuse side without authority"),
Operation("write click metric", "eventual count is acceptable", "accept locally and reconcile"),
]
for partitioned in (False, True):
print("PARTITION" if partitioned else "HEALTHY")
for op in ops:
if not partitioned:
result = "serve normally; network can coordinate"
else:
result = op.partition_policy
print(f"- {op.name:18} | {result}")
print()
print("CAP C is a single-copy/linearizability-style visibility property in the theorem.")
print("ACID C means a transaction preserves declared database/application invariants.")
Expected output
HEALTHY
- browse catalog | serve normally; network can coordinate
- reserve last unit | serve normally; network can coordinate
- write click metric | serve normally; network can coordinate
PARTITION
- browse catalog | serve local replica
- reserve last unit | refuse side without authority
- write click metric | accept locally and reconcile
CAP C is a single-copy/linearizability-style visibility property in the theorem.
ACID C means a transaction preserves declared database/application invariants.
The healthy branch is the important corrective: no theorem requires the service to throw away either consistency or availability when required communication is working. The partition branch shows why the choice belongs to the operation and invariant.
Check your understanding
- Why is “pick two” especially misleading when the network is healthy?
- How does CAP consistency differ from ACID consistency?
- Can one application reasonably serve catalog reads during a partition while refusing inventory reservations?
- Why is classifying an entire database product as permanently AP or CP often insufficient?
- What should replace the product label in an architecture decision record?
Review the answers
The impossibility is triggered by a partition that blocks needed communication. In healthy operation, a design may provide both successful responses and linearizable behavior.
CAP consistency concerns one-copy/real-time visibility across replicas; ACID consistency concerns preserving declared integrity rules through transactions.
Yes. Their invariants and tolerated anomalies differ, so their degraded modes can differ even on the same platform.
Products expose multiple operations, consistency levels, routing modes, and topologies; behavior can change by configuration and failure state.
Write the operation, invariant, required participants, accepted anomalies, partition/degraded behavior, recovery path, and observable signals.
7. Production judgment and bridge
Use CAP as a fault-condition theorem, not a procurement quadrant. Architecture reviews should capture the exact object/operation, fault model, authority assumptions, client contract, and recovery behavior. Tests should include healthy operation, minority isolation, asymmetric reachability, and healing. Metrics should distinguish successful-but-stale responses from rejected-for-safety responses rather than flattening both into one availability number.
The next lesson extends the reasoning beyond faults. Even when every node can communicate, coordinating across distance costs time. PACELC gives a compact lens for that healthy-network latency-versus-consistency tension.
Authoritative references
- Gilbert & Lynch — CAP theorem formalization — the conditional impossibility result under partition
- Herlihy & Wing — Linearizability — clarifies the consistency notion commonly used when explaining CAP
- Daniel Abadi — Consistency Tradeoffs in Modern Distributed Database System Design — explains why CAP alone is not enough to characterize normal-operation tradeoffs