25 min read Caching, Redis & Memory Systems Lesson 14 of 15
Part 4 — Modern Data Systems, Scale & Analytics

Lesson 14 — Caching: Redis & Rapid Data Access

Cache Hierarchy, Cache-Aside, TTL, Invalidation & High-Scale Architecture

In the previous lesson, we explored how distributed databases scale under heavy load. We learned Vertical Scaling, Replication, Read Replicas, Partitioning, and Sharding.

Yet even after scaling a database cluster, a persistent, fundamental bottleneck remains. Consider a web platform where thousands of concurrent users view the exact same product page. Every inbound request prompts the application server to query the database: "Fetch this product's record." The database retrieves the row from disk and returns the result. Moments later, another wave of users views the same product, executing the identical query against disk.

Continuously re-reading identical, unchanging data directly from database storage introduces enormous, wasteful overhead. That motivates a pivotal architectural question:

"Can data that is repeatedly needed in the exact same format be staged in an ultra-fast layer?"

Yes! This is the domain of modern distributed computing's greatest performance multiplier: Caching.

What You Will Master in This Lesson:

The foundational pillars of high-throughput caching architectures:

  • Cache Fundamentals: Cache Hit, Cache Miss, and Cache-Aside pattern.
  • Cache Hierarchy: Browser, CDN Edge, Application, and Database buffer pool.
  • Redis Capabilities: Why RAM is fast and understanding Redis as a data store.
  • TTL & Invalidation: Time-to-Live bounds and solving stale data anomalies.
  • Write Strategies: Cache-Aside, Write-Through, and Write-Back (Write-Behind).
  • Eviction & Stampede: LRU algorithm and mitigating Thundering Herd spikes.

1 What is a Cache? Concept & Real-World Example

In straightforward software engineering terms:

"A cache is a high-speed data storage layer that stores a subset of frequently accessed data, allowing subsequent requests to be served much faster than accessing the primary storage source."
Conceptual Architecture:
Original Data (Database)
     ↓
   Cache (In-Memory)
     ↓
Repeated Requests (Fast)
          

The ultimate objective of a cache is singular: Never execute expensive, repetitive work twice.

Real-World Case (Byteion Academy):

Suppose the Byteion Academy homepage curriculum list is backed by a database. 10,000 students load the homepage at 9:00 AM:

Without Cache: 10,000 Requests → Database → 10,000 Disk Reads

With Cache: 10,000 Requests → Redis Cache → 0 Database Load!

2 Where Does a Cache Live? The Modern Cache Hierarchy

Caching is not confined to Redis alone. In modern web architectures, cache layers exist across every hop from the user's browser down to storage platters:

1. Browser Cache

HTML, CSS, JS and images cached on the client device.

2. CDN Edge Cache

Cloudflare or Fastly edge points serving regional requests.

3. Application Cache (Redis)

Shared distributed in-memory store for application nodes.

4. Database Buffer Pool

PostgreSQL internal 8KB disk pages cached in memory.

Golden Performance Rule: There is never a requirement that every user request must reach the relational database. If a request can be answered by an earlier caching layer, return the response immediately. This keeps the primary database pristine and resilient.

3 Cache Hit, Cache Miss & The Cache-Aside Pattern

When an application inspects a cache for data, two foundational outcomes occur:

Cache Hit

The application finds the requested entity active in memory.

Request → Cache → Found ✅ → Return Data (~0.4ms)
(Database is bypassed entirely!)
          
Cache Miss

The entity is absent from the cache; the application must fetch it from storage.

Request → Cache → Not Found ❌ 
→ Database → Read Data → Store in Cache → Return Data
          

How Cache-Aside (Lazy Loading) Operates

In production software, the most prevalent caching pattern is Cache-Aside. The application code explicitly coordinates both stores:

1. Client requests: GET /products/101

2. App executes: redis.get("product:101")

   ├── HIT: Redis returns { "id": 101, "name": "Laptop", "price": 80000 } → Return response!

   └── MISS: Redis returns nil

       ├── App queries DB: SELECT * FROM products WHERE id=101

       ├── App populates Redis: redis.set("product:101", json_data, ex=300)

       └── App returns fresh payload to Client

4 What is Redis? Why RAM is Fast & The Source of Truth

Redis (Remote Dictionary Server) is a widely deployed open-source In-Memory Data Store designed fundamentally around atomic Key → Value operations:

user:1001
→ User JSON Profile
product:101
→ Product Specifications
session:abc
→ Auth Token & State

Is Redis a Database?

Yes! Redis is a standalone data store with full persistence capabilities (RDB snapshots and AOF logs). In distributed architectures, however, Redis serves multiple distinct roles: Cache, Session Store, Distributed Lock Provider, Atomic Rate Limiter, and Message Broker. Always remember: "Redis is much more than a cache, but for caching it is unmatched."

Is Cache a Database Replacement? The Source of Truth

No. A cache is never a permanent replacement for a primary database. The Database is the Source of Truth—the permanent, durable ledger of authoritative record. The Cache is a Fast Derived Copy. If a cache cluster crashes or memory is entirely purged, the system easily recovers by re-fetching data from the persistent database.

5 TTL (Time To Live) & Cache Invalidation

The most critical trade-off in caching design is determining: "How long should cached data remain valid in memory?"

TTL (Time To Live) — Automatic Expiration

Every key is assigned a finite lifespan. For instance, TTL = 300 seconds (5 minutes). Once 5 minutes elapse, Redis evicts the entry automatically. The next inbound query incurs a cache miss and refreshes memory with the latest state.

Store Cache → 5 Minutes Pass → Expired → Next Request → Database → Refresh Cache
Does TTL Solve All Problems? Why Invalidation is Hard

Suppose a product price is \$800 in the database, cached with a 1-hour TTL. 5 minutes later, an administrator reduces the price to \$750. If the application does not actively invalidate the cache key, customers will continue seeing and ordering at the old \$800 price for the remaining 55 minutes!

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton

Because data is replicated across Browsers, CDNs, Edge gateways, and Redis, synchronizing cache purges across distributed systems is an intricate distributed consistency challenge.

6 Write Strategies: Write-Through, Write-Back & Read-Through

How your application synchronizes updates between memory and persistent storage dictates durability and write throughput:

Synchronous

Write-Through

The application writes to the cache, which synchronously updates the primary database before confirming success.

Pros: Cache and DB remain 100% consistent.
Cons: Higher write latency overhead.
Asynchronous

Write-Back (Write-Behind)

The application writes to memory with instant response (~0.4ms). Dirty buffers are asynchronously flushed to the database in bulk batches.

Pros: Extreme write throughput (telemetry, view counters).
Cons: Risk of data loss if memory crashes before flush.
Automated Read

Read-Through

The application treats the cache as the single datastore interface. On miss, the cache library retrieves from storage transparently.

Pros: Simplifies application business logic.

7 Memory Exhaustion: Eviction Policies & LRU

System RAM is finite. If Redis is provisioned with 8 GB of memory and data volume reaches 10 GB, the engine must purge older keys to make room. This mechanism is known as Cache Eviction.

How LRU (Least Recently Used) Works

The core philosophy of LRU: "The key that has not been accessed for the longest duration of time is purged first."

A → Accessed 2 seconds ago (Recently used)

B → Accessed 5 seconds ago (Recently used)

C → Accessed 10 minutes ago (Not used for long)

D → Accessed 30 minutes ago (Not used for long)

On memory exhaustion: Key D is evicted immediately!

8 Cache Stampede (Thundering Herd) & Cache Warming

Imagine a super-hot key (e.g., homepage:courses) sustaining 20,000 requests per second. At that exact millisecond, its TTL expires!

Cache Stampede (Thundering Herd)

The instant the key expires, all 20,000 concurrent requests encounter a simultaneous cache miss and slam into the primary database simultaneously. Database connections exhaust instantly and the service crashes.

20,000 Requests → Simultaneous Cache Miss → 20,000 Complex DB Queries → CRASH!

Mutex Locking (Single Flight)

When a miss occurs, only the first request acquires a lock to query the database. All remaining callers sleep for 2ms and receive the warm result from cache once refreshed.

Cache Warming (Pre-Loading)

Immediately following a deployment or restart, scripts pre-warm the cache with popular records so initial users never experience cold cache misses.

9 Production Realities: Passwords, Session Stores & Rate Limiting

In real-world distributed architectures, not all data should or can be cached:

Should Passwords Ever Be Cached?

Never! Caching plaintext credentials in memory creates an egregious security vulnerability. Authentication must always rely on salted cryptographic hashes (Bcrypt, Argon2).

Centralized Session Cache:

In an autoscaled cluster of web servers, a centralized Redis cluster maintains user authentication sessions, allowing any app server to validate incoming requests seamlessly.

API Rate Limiting with Redis:

To enforce 100 requests per minute per client, use Redis's atomic counters: INCR rate:user:847291 paired with EXPIRE 60.

10 Cache Key Design, Versioning & Hit Rate Metrics

A robust caching architecture depends heavily on consistent, explicit key namespacing:

Cache Key & Namespace Design:
user:1001:profile
user:1001:settings
product:101:details
order:5001:items
          

Cache Versioning: When data schemas mutate, embed version tokens: product:v2:101. New code reads modern structures without legacy deserialization errors.

Cache Hit Rate Calculation:
Hit Rate = (Total Hits / Total Requests) × 100%

If 9,000 out of 10,000 requests hit memory, Hit Rate = 90% and Miss Rate = 10%. Higher hit rates correlate directly with lower database CPU and I/O utilization.

11 The Complete Production Mental Model

Synthesizing Lessons 13 and 14, our enterprise data architecture now takes complete shape:

                           USER
                            ↓
                     LOAD BALANCER
                            ↓
                   APPLICATION SERVERS
                            ↓
                ┌───────────┴───────────┐
                ↓                       ↓
             [READ]                  [WRITE]
                ↓                       ↓
          REDIS CACHE            PRIMARY DATABASE
          (In-Memory)           (Postgres Master)
          Hits: ~0.4ms                  │
                                        ├── WAL Streaming
                                        ↓
                                  READ REPLICAS
                               (Scale-Out Read Traffic)
        
When Should You NOT Use a Cache? If data is rarely accessed, primary database queries execute in sub-millisecond seek times, data changes every second, or strict financial consistency is paramount—bypass the cache and rely directly on persistent ACID storage.

Interactive Caching & Performance Arena

Simulate caching patterns, LRU/LFU evictions, and disaster defenses live

Select Caching Pattern:

Cache-Aside: Application queries the cache first. On a cache miss, it reads from PostgreSQL and populates the cache for subsequent callers.

Application Server
App Layer
Status: Idle
In-Memory Cache
Redis (RAM)
product:101 → { name: 'Laptop', price: 80000 }
Latency: ~0.4ms
Persistent Storage
PostgreSQL (SSD)
Rows: 10,000,000
Latency: ~22ms
Execution Pipeline Log: Latency: 0.0ms
> Click any operation button above to observe the real-time architectural flow.

Knowledge Check: Caching & In-Memory Mastery

1. In an e-commerce platform, an admin updates a product price directly in PostgreSQL but fails to invalidate or update the Redis cache. What symptom will users encounter?

2. If an adversary deliberately bombs your system with millions of non-existent entity IDs to bypass the cache and exhaust the database, what is this attack named and how is it mitigated?

3. What is the gold-standard engineering defense to prevent a devastating Cache Avalanche (Stampede) during mass expirations?

Summary: Key Takeaways from Lesson 14

  • Cache: An auxiliary fast copy of frequently accessed data to eliminate repetitive database work.
  • Source of Truth: The persistent database is the definitive ledger; the cache is a performance optimization layer.
  • Cache-Aside: The standard lazy-loading pattern in modern systems; only cache misses incur a trip to persistent storage.
  • Eviction Policies: LRU and LFU prevent memory exhaustion by systematically pruning low-value keys.
  • Stampede & Avalanche: Defend via single-flight mutex locks, request coalescing, and randomized jitter TTLs.