PACELC Theorem
Beyond CAP: The Latency Factor
Section titled “Beyond CAP: The Latency Factor”The CAP theorem tells us what happens during partitions, but what about normal operation? That’s where PACELC comes in.
What is PACELC?
Section titled “What is PACELC?”PACELC extends CAP by adding latency considerations:
If there’s a Partition (P): choose between Availability and Consistency
Else (E) (normal operation): choose between Latency and Consistency
Key Insight: Even when there’s no partition, you still face a trade-off: fast responses (low latency) vs accurate data (consistency).
The Two Scenarios
Section titled “The Two Scenarios”Scenario 1: During Partition (P-A-C)
Section titled “Scenario 1: During Partition (P-A-C)”This is the CAP part we already know:
Same as CAP: During partitions, choose CP or AP.
Scenario 2: Normal Operation (E-L-C)
Section titled “Scenario 2: Normal Operation (E-L-C)”This is the new part PACELC adds:
Key Insight: Even when everything works perfectly, you still choose between speed and accuracy.
Understanding the E-L-C Trade-off
Section titled “Understanding the E-L-C Trade-off”Low Latency → Eventual Consistency
Section titled “Low Latency → Eventual Consistency”When you prioritize low latency, you accept eventual consistency:
Example: Reading from a local cache (fast, but might be outdated) vs reading from the primary database (slower, but always accurate).
Strong Consistency → Higher Latency
Section titled “Strong Consistency → Higher Latency”When you prioritize consistency, you accept higher latency:
Example: Asynchronous replication (fast, but eventual) vs synchronous replication (slower, but consistent).
Real-World Examples
Section titled “Real-World Examples”Example 1: E-Commerce Product Page
Section titled “Example 1: E-Commerce Product Page”Choice: Most e-commerce sites choose low latency for product pages (cache) but consistency for checkout (database).
Example 2: Social Media Feed
Section titled “Example 2: Social Media Feed”Choice: Social media prioritizes low latency (read from nearby replica) over perfect consistency.
Example 3: Bank Balance Check
Section titled “Example 3: Bank Balance Check”Choice: Banking systems prioritize consistency over latency. Users accept slower responses for accurate data.
The Four Combinations
Section titled “The Four Combinations”PACELC gives us four possible combinations:
PA-EL: Availability + Low Latency
Section titled “PA-EL: Availability + Low Latency”During partition: Choose availability
Normal operation: Choose low latency
Examples: DNS, CDN, most caching systems
Characteristics:
- ✅ Always available
- ✅ Fast responses
- ❌ May serve stale data
PA-EC: Availability + Consistency
Section titled “PA-EC: Availability + Consistency”During partition: Choose availability
Normal operation: Choose consistency
Examples: Cassandra (with tunable consistency), DynamoDB (with strong consistency reads)
Characteristics:
- ✅ Available during partitions
- ✅ Consistent during normal operation
- ⚠️ Slower during normal operation
PC-EL: Consistency + Low Latency
Section titled “PC-EL: Consistency + Low Latency”During partition: Choose consistency
Normal operation: Choose low latency
Examples: MongoDB (with strong consistency, but optimized for speed)
Characteristics:
- ✅ Consistent during partitions
- ✅ Fast during normal operation
- ❌ May reject requests during partitions
PC-EC: Consistency + Consistency
Section titled “PC-EC: Consistency + Consistency”During partition: Choose consistency
Normal operation: Choose consistency
Examples: Traditional relational databases (PostgreSQL, MySQL)
Characteristics:
- ✅ Always consistent
- ❌ Slower (synchronous replication)
- ❌ May reject requests during partitions
Tuning PACELC Per Operation
Section titled “Tuning PACELC Per Operation”Example: An e-commerce system might:
- Product pages: PA-EL (fast, cached)
- Checkout: PC-EC (consistent, accurate)
- Inventory: PC-EC (consistent, can’t oversell)
LLD ↔ HLD Connection
Section titled “LLD ↔ HLD Connection”How PACELC choices affect your method design:
Low Latency → Async Operations
Section titled “Low Latency → Async Operations”When prioritizing latency, use asynchronous patterns:
1import asyncio2from typing import Optional3
4class LowLatencyService:5 def __init__(self):6 self._cache = {} # Local cache for fast reads7
8 async def read(self, key: str) -> Optional[object]:9 # Read from cache first (low latency)10 if key in self._cache:11 return self._cache[key] # Fast!12
13 # Fallback to DB if not in cache14 return await self._read_from_db(key)15
16 async def write(self, key: str, value: object):17 # Write to cache immediately (low latency)18 self._cache[key] = value19
20 # Replicate asynchronously (eventual consistency)21 asyncio.create_task(self._replicate_async(key, value))1import java.util.*;2import java.util.concurrent.*;3
4public class LowLatencyService {5 private Map<String, Object> cache = new ConcurrentHashMap<>(); // Local cache6
7 public CompletableFuture<Object> read(String key) {8 // Read from cache first (low latency)9 Object cached = cache.get(key);10 if (cached != null) {11 return CompletableFuture.completedFuture(cached); // Fast!12 }13
14 // Fallback to DB if not in cache15 return readFromDb(key);16 }17
18 public void write(String key, Object value) {19 // Write to cache immediately (low latency)20 cache.put(key, value);21
22 // Replicate asynchronously (eventual consistency)23 CompletableFuture.runAsync(() -> replicateAsync(key, value));24 }25}Consistency → Sync Operations
Section titled “Consistency → Sync Operations”When prioritizing consistency, use synchronous patterns:
1from threading import Lock2
3class ConsistentService:4 def __init__(self):5 self._data = {}6 self._lock = Lock()7 self._replicas = [] # List of replica nodes8
9 def write(self, key: str, value: object) -> bool:10 with self._lock:11 # Write to primary synchronously12 self._data[key] = value13
14 # Replicate to all replicas synchronously (consistency)15 for replica in self._replicas:16 if not replica.set(key, value): # Wait for each17 return False # Fail if any replica fails18
19 return True # Only return success when all updated1import java.util.*;2import java.util.concurrent.locks.ReentrantLock;3
4public class ConsistentService {5 private Map<String, Object> data = new HashMap<>();6 private final ReentrantLock lock = new ReentrantLock();7 private List<Replica> replicas = new ArrayList<>();8
9 public boolean write(String key, Object value) {10 lock.lock();11 try {12 // Write to primary synchronously13 data.put(key, value);14
15 // Replicate to all replicas synchronously (consistency)16 for (Replica replica : replicas) {17 if (!replica.set(key, value)) { // Wait for each18 return false; // Fail if any replica fails19 }20 }21
22 return true; // Only return success when all updated23 } finally {24 lock.unlock();25 }26 }27}Decision Framework
Section titled “Decision Framework”Use this framework to choose your PACELC combination:
| Use Case | PACELC Choice | Why |
|---|---|---|
| Bank balance | PC-EC | Accuracy > Speed |
| Product page | PA-EL | Speed > Perfect accuracy |
| Checkout | PC-EC | Accuracy > Speed |
| Social feed | PA-EL | Speed > Perfect accuracy |
| Inventory | PC-EC | Accuracy > Speed (can’t oversell) |
Key Takeaways
Section titled “Key Takeaways”What’s Next?
Section titled “What’s Next?”Now that you understand consistency trade-offs, let’s explore how to maintain consistency across multiple operations:
Next up: Distributed Transactions — Learn how to coordinate multiple operations across distributed systems using 2PC, Saga pattern, and compensation.