3.1.2. Application-Level Caching: ElastiCache and CloudFront
💡 First Principle: A cache intercepts expensive operations and serves the result from fast memory instead. The economics are compelling: a database query that takes 50ms and consumes database CPU can become a cache hit that takes 0.5ms and costs nothing. Caching is frequently the highest-ROI reliability improvement available.
Without caching, every user request hits the database. Under heavy load, the database becomes the bottleneck — it queues requests, query latency grows, and eventually the whole application slows or fails. Caching breaks this dependency for frequently accessed, slowly changing data.
Amazon ElastiCache is a managed in-memory caching service supporting two engines:
| Feature | Redis | Memcached |
|---|---|---|
| Data structures | Rich (lists, sets, hashes, sorted sets, streams) | Simple strings only |
| Persistence | ✅ Yes (RDB snapshots, AOF logging) | ❌ No |
| Replication | ✅ Yes (read replicas) | ❌ No |
| Multi-AZ failover | ✅ Yes (automatic) | ❌ No |
| Pub/Sub messaging | ✅ Yes | ❌ No |
| Horizontal scaling | ✅ Cluster mode with sharding | ✅ Multi-node |
| Use when | Sessions, leaderboards, pub/sub, complex data | Simple caching, multi-threaded scaling |
Redis cluster mode and Multi-AZ: with cluster mode disabled, one shard holds the whole dataset (a primary plus up to 5 replicas), so data size is bounded by one node's memory. With cluster mode enabled, the keyspace is partitioned across multiple shards, each with its own primary and replicas, so the dataset and write throughput scale out. Multi-AZ with automatic failover works in both modes: if the primary fails, ElastiCache promotes the replica with the least replication lag, writes resume within seconds, and the primary endpoint's DNS name follows the new primary.
Caching Strategies:
| Strategy | How It Works | Best For |
|---|---|---|
| Cache-Aside (Lazy Loading) | Application checks cache first; on miss, reads DB and populates cache | Read-heavy workloads; only caches what's requested |
| Write-Through | Application writes to cache AND DB on every write | Data must always be fresh in cache; higher write cost |
| Write-Behind (Write-Back) | Write to cache immediately; async flush to DB | High write throughput; risk of data loss if cache fails |
| Read-Through | Cache library fetches from DB automatically on miss | Simplifies application code |
TTL (Time to Live): Every cached item should have a TTL — the maximum time it stays in cache before expiring. Without TTL, stale data accumulates. With TTL too short, your cache hit rate drops and you lose the performance benefit. Setting TTL requires understanding how often your data changes and how stale is acceptable. Add random jitter to TTLs so keys cached at the same moment don't all expire together and send a burst of misses to the database (a cache stampede).
CloudFront for Static and Dynamic Content:
CloudFront caches content at AWS edge locations globally. For caching purposes, CloudFront is the right choice when:
- Content is served to geographically distributed users
- Objects are static or change infrequently (images, CSS, JS, API responses with caching headers)
- You want to absorb traffic spikes at the edge rather than hitting your origin
ElastiCache is application-layer caching (your app code controls what's cached). CloudFront is network-layer caching (HTTP responses cached at edge).
⚠️ Exam Trap: ElastiCache Redis is the exam's default answer for session storage because it supports persistence and replication. Memcached doesn't persist data — if a Memcached node fails, all cached data is lost and every subsequent request hits the database (cache stampede risk). For production session stores, Redis is the correct choice.
Reflection Question: An e-commerce site uses ElastiCache Memcached for session storage. During a node failure, 10,000 users are suddenly logged out and all hit the database simultaneously, causing an outage. What two architectural changes address this problem?