8.2 Caching Strategies and ElastiCache Patterns
Key Takeaways
- Lazy Loading (cache-aside) reads cache first, and on a miss reads the database, writes the result to cache, then returns — only requested data is cached but the first read always misses (cold start).
- Write-Through writes to cache and database together so cached data is never stale, at the cost of write latency and caching data that may never be read.
- TTL (Time-to-Live) bounds staleness and stops unbounded cache growth; pair it with lazy loading + write-through for the recommended combined pattern.
- ElastiCache for Redis supports replication, Multi-AZ failover, persistence, sorted sets, pub/sub, and geospatial data; Memcached is multi-threaded, simple, and has no persistence or replication.
- Storing sessions in ElastiCache for Redis (or DynamoDB) makes app servers stateless, enabling clean horizontal scaling and removing the need for ALB sticky sessions.
Quick Answer: Lazy loading = cache-aside (check cache; on miss read DB, fill cache, return). Write-through = write cache + DB together (never stale, but write overhead). TTL auto-expires entries. Use Redis for persistence, Multi-AZ failover, sorted sets, and pub/sub; use Memcached for simple multi-threaded key-value caching. Move sessions into Redis to make app servers stateless and scale horizontally.
Caching Strategies
Lazy Loading (Cache-Aside)
- App checks the cache.
- Hit → return cached data (fast).
- Miss → read the database, write the result to cache, return.
| Advantage | Disadvantage |
|---|---|
| Only data that is actually requested is cached | Every cache miss adds a round trip (cold-start latency) |
| A cache node failure does not break the app | Data can go stale (no auto-refresh) |
| Simple to implement | First request for any key always misses |
Write-Through
The app writes to cache AND database on every write, so reads always hit fresh data.
| Advantage | Disadvantage |
|---|---|
| Cached data is never stale | Extra write latency on every update |
| Reads are reliably fast | Caches data that may never be read |
Recommended combined pattern
Use lazy loading + write-through + TTL together: write-through keeps actively updated keys fresh, lazy loading populates read-only keys on demand, and TTL caps staleness and reclaims memory. The exam treats 'minimize stale data' as a write-through signal and 'reduce read latency / offload the database' as a lazy-loading signal.
Choosing a TTL
| Data change rate | Suggested TTL |
|---|---|
| Real-time (stock/ticker) | 5–30 seconds |
| Frequently changing (inventory) | 1–15 minutes |
| Slowly changing (user profiles) | 1–24 hours |
| Rarely changing (config, static) | 1–7 days |
Common Trap: A 'thundering herd' happens when a popular key expires and many requests miss simultaneously and stampede the database. Mitigate with slightly randomized (jittered) TTLs or pre-warming hot keys.
Session Store Pattern
Keeping session state on individual EC2 instances forces ALB sticky sessions and loses carts when an instance fails or scales in.
| Without ElastiCache | With ElastiCache (Redis) |
|---|---|
| Sessions live on each app server | Sessions centralized in Redis |
| ALB sticky sessions required | Any server serves any user |
| Losing a server loses its sessions | Server loss does not lose sessions |
| Uneven load distribution | App servers are stateless → free horizontal scaling |
On the Exam: 'Make app servers stateless for Auto Scaling' → store sessions in ElastiCache for Redis (or DynamoDB). 'Reduce repeated identical database reads' → add ElastiCache with lazy loading.
Redis vs. Memcached
ElastiCache offers three engines: Redis OSS, Valkey (an open-source Redis fork AWS now offers at lower cost), and Memcached. For the exam, the decisive split is Redis-family (rich features) vs Memcached (simple).
| Choose Redis / Valkey when you need… | Choose Memcached when you need… |
|---|---|
| Persistence (snapshots / AOF) | Pure, simple key-value caching |
| Multi-AZ with automatic failover | Maximum simplicity, no failover |
| Read replicas / replication | Multi-threaded scale-up on large nodes |
| Complex types (lists, sets, sorted sets for leaderboards) | Sharded horizontal scaling of plain objects |
| Pub/sub messaging, geospatial, Lua scripting | No persistence requirement |
Key exam tells: leaderboard / ranking → Redis sorted sets; persistence or failover → Redis; simplest possible cache, multi-threaded → Memcached.
Cache Invalidation
| Method | How | Use case |
|---|---|---|
| TTL | Entries auto-expire | General default |
| Explicit delete | App deletes the key on update | Known data changes |
| Event-driven | DynamoDB Streams / SNS / EventBridge updates the cache | Near-real-time consistency |
Beyond ElastiCache
ElastiCache is in-memory caching for application-tier data and sessions. Do not confuse it with DynamoDB Accelerator (DAX), an in-memory cache specific to DynamoDB that requires no application code change, or with CloudFront, which caches HTTP responses at edge locations. A 'cache DynamoDB reads with microsecond latency and no code change' scenario points to DAX, not ElastiCache.
Worked Example: Sizing a Read-Heavy Cache
Suppose a product-catalog page is read 10,000 times per second but the underlying items change only a few times per hour. Without caching, every request hits RDS, forcing a large, expensive instance and read replicas just to survive. Add ElastiCache for Redis with lazy loading and a 5-minute TTL: after the cache warms, the cache-hit ratio approaches 99%, so RDS sees roughly 100 reads/second instead of 10,000. The database can shrink, replication lag disappears, and p99 read latency drops from tens of milliseconds to sub-millisecond. This is the canonical 'reduce database load and latency' answer.
Now contrast a checkout-price scenario where a stale price for even seconds is unacceptable. Here lazy loading alone is risky; pair write-through (update the cache whenever the price is written) with a short TTL as a safety net. The pattern you choose is dictated by the staleness tolerance stated in the question.
Multi-AZ and Failover Details
For Redis, a replication group has one primary and up to five read replicas across AZs. With Multi-AZ enabled, ElastiCache automatically promotes a replica to primary on failure and updates the primary endpoint DNS — typically within seconds. Memcached has no replication or failover; a lost node simply loses its slice of cached data, which is acceptable only for pure caches that can repopulate from the database. If a question demands cache durability or automatic failover, Memcached is eliminated immediately.
| Requirement | Engine answer |
|---|---|
| Automatic failover, replica promotion | Redis Multi-AZ |
| Survive node loss without data loss | Redis with replicas + backups |
| Cheapest pure cache, repopulates from DB | Memcached |
A read-heavy application is adding caching, but the team is most worried about ever serving stale data. Which approach minimizes staleness?
An online game must display a real-time global leaderboard ranking millions of players, with sub-millisecond updates and durable failover. Which ElastiCache choice fits best?