Bonus F
PACELC — Beyond CAP Theorem
CAP theorem's blind spot
CAP theorem gets quoted constantly in system design discussions, usually as: "you can only have two of Consistency, Availability, and Partition tolerance." That's true, but it's also almost useless as a day-to-day design tool, for one specific reason: it only describes what happens during a network partition.
Network partitions — where nodes in a distributed system genuinely can't communicate with each other — are, for most systems, rare. They might happen for a few minutes a few times a year. CAP theorem has nothing to say about the other 99.9% of the time, when the network is working fine and nodes can talk to each other without any trouble.
That's the gap PACELC fills.
What PACELC actually says
PACELC theorem, introduced by Daniel Abadi, extends CAP into two conditions:
Partition — if there is a network partition, you choose between Availability and Consistency (this is exactly CAP theorem, unchanged).
Else — if there is no partition, you still choose between Latency and Consistency.
That second half is the part most engineers miss. Even when everything is working normally, a distributed database still has to decide: does a write need to be confirmed by every replica before it's considered successful (higher consistency, higher latency), or is it considered successful as soon as it hits one node, with replication happening asynchronously in the background (lower latency, weaker consistency guarantees)?
Why the "else" case matters more in practice
Think about how often each condition actually applies for a typical production system:
- Partition case: rare. A regional network split, a data-center-to-data-center link going down, a misconfigured firewall. When it happens, it's usually a major incident, but the frequency is low.
- Else case: constant. Every single write, every single moment the system is running normally, this trade-off is live. It's the default operating condition, not the exception.
A database's behavior during the "else" case is what your users experience essentially all the time. A database's behavior during a partition is what your users experience during an outage. Both matter, but if you're only reasoning about the partition case because that's what CAP theorem talks about, you're optimizing for the rare event and ignoring the trade-off that's actually shaping your system's everyday latency and consistency profile.
Classifying real databases with PACELC
PACELC gives a more precise way to classify systems than CAP alone:
- PC/EC — during a partition, prioritize consistency; during normal operation, also prioritize consistency (accept higher latency for stronger guarantees both times). Traditional relational databases with synchronous replication fall here.
- PA/EL — during a partition, prioritize availability; during normal operation, prioritize latency (accept weaker consistency both times for speed and uptime). Cassandra with default settings is a classic example — fast, available, eventually consistent, by design, not just under failure.
- PA/EC — available during a partition, but consistent during normal operation. Some configurations of MongoDB behave this way, depending on write/read concern settings.
- PC/EL — consistent during a partition (sacrificing availability), but favoring latency during normal operation. Less common, but achievable with tunable systems.
Notice that a single database technology isn't locked into one of these — many modern distributed databases let you tune the else-case behavior per operation, per collection, or globally, via read/write concern or consistency-level settings. That configurability is exactly why understanding PACELC matters: the "right" setting isn't a property of the database, it's a property of the specific data and access pattern you're using it for.
A concrete example: the "likes" counter vs. the account balance
Say your application has both a "likes" counter on posts and an account balance in a payments table, both stored in the same distributed database with tunable consistency.
For the likes counter, tune toward the L side of "else": accept that a like might take a moment to show up on someone else's screen, in exchange for the write completing fast and never blocking on cross-node coordination. Nobody is harmed by a like count being off by one for 200 milliseconds.
For the account balance, tune toward the C side of "else": require the write to be acknowledged by enough replicas to guarantee the next read sees it, even if that adds real latency to every balance update. A stale balance read is a correctness bug, not a cosmetic delay.
This is the practical payoff of PACELC: it gives you the vocabulary to make that distinction per use case within the same system, rather than treating "our database is eventually consistent" or "our database is strongly consistent" as one blanket property that applies uniformly to everything you store in it.
The takeaway
CAP theorem is correct but incomplete for design purposes — it answers a question you'll face rarely. PACELC adds the question you'll face constantly: when nothing is wrong, do you want speed or certainty? Answering that deliberately, per data type, is a sharper tool than reciting "consistency, availability, partition tolerance, pick two" and calling the analysis done.
Next in the series: Blog 7 picks the thread back up on message queues and event-driven architecture — where the latency-vs-consistency trade-off from this post shows up again, this time in the form of "how long can a consumer lag behind a producer before it matters."