> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cache Aside with Redis

> Demonstrates Redis cache-aside pattern to accelerate reads, show cache hits and misses, and illustrate stale data when the database is updated without cache invalidation.

In this lesson you'll place a Redis cache in front of your database to accelerate read requests. You'll measure response behavior before and after adding the cache, then modify the underlying database and observe the application returning stale data because it was served from Redis.

This demonstrates the cache-aside (lazy-loading) pattern: on a cache miss the application reads from the database and populates Redis; on a cache hit it serves data directly from Redis. If the database changes and the cache is not invalidated or updated, the application may continue returning stale data until the cache entry expires or is refreshed.

Here is an example interaction showing a request for a user profile, a repeated request (served from cache), and a short look at the application logs:

```bash theme={null}
controlplane ~ on ☁️ (us-east-1) ➔ curl localhost:8000/profile/7
{"id": 7, "bio": "Original bio for user 7."}

# Repeat the same request; this may be served from cache
controlplane ~ on ☁️ (us-east-1) ➔ curl localhost:8000/profile/7
{"id": 7, "bio": "Original bio for user 7."}

# Inspect recent application logs
controlplane ~ on ☁️ (us-east-1) ➔ docker compose logs app | tail -2
# (example log lines)
app_1  | INFO  cache: hit for profile 7
app_1  | INFO  response served from cache
```

<Callout icon="lightbulb" color="#1CB2FE">
  This lesson demonstrates the cache-aside pattern: on a cache miss the application reads from the database and populates Redis; on a cache hit it serves data directly from Redis. If the database is updated without invalidating or updating the cache, the application may continue to serve stale data until the cache entry expires or is refreshed.
</Callout>

## What you'll observe

* Baseline: requests read directly from the database (no Redis), with typical latency.
* After adding Redis: first request for an item populates the cache (cache miss → DB read); subsequent requests for the same item are served from Redis (cache hit), reducing latency.
* Stale data scenario: if you update the database directly without invalidating the Redis entry, the application may return the old value until the cached key expires or is explicitly refreshed/invalidated.

## Quick commands and examples

| Action                | Command / Example                              | Notes                                            |
| --------------------- | ---------------------------------------------- | ------------------------------------------------ |
| Request profile       | `curl localhost:8000/profile/7`                | Hits app endpoint that uses cache-aside logic    |
| Repeat request        | `curl localhost:8000/profile/7`                | Likely a cache hit on subsequent call            |
| View app logs         | `docker compose logs app \| tail -2`           | Look for `cache: hit` or `cache: miss` lines     |
| Example JSON response | `{"id": 7, "bio": "Original bio for user 7."}` | Response format returned by the profile endpoint |

## How the cache-aside pattern works (summary)

1. Application receives a request for resource X.
2. Check Redis for key X:
   * If present (cache hit): deserialize and return to client.
   * If absent (cache miss): read X from the database, return to client, and write X into Redis (optionally with a TTL).
3. If the database is modified by another process, the cache must be invalidated or updated to avoid serving stale data. Common strategies are: write-through, write-behind, explicit invalidation, or short TTLs.

## Debugging tips

* Look for log lines indicating cache behavior, e.g. `cache: hit for profile 7` or `cache: miss for profile 7`.
* When debugging stale reads:
  * Verify if the database row actually changed.
  * Check whether the Redis key still exists and contains the old value.
  * Confirm whether your application invalidates cache keys on updates.
* Use Redis CLI to inspect keys: `redis-cli GET profile:7` (or the key format your app uses).

## Common invalidation strategies

| Strategy                  | Description                                                     | When to use                                              |
| ------------------------- | --------------------------------------------------------------- | -------------------------------------------------------- |
| Explicit invalidation     | On DB update, delete or update the corresponding cache key      | Works when all writes go through the application         |
| Short TTL                 | Set a short expiration on cache entries                         | Useful if occasional staleness is acceptable             |
| Write-through             | Write to cache and DB synchronously on updates                  | Ensures cache is up-to-date but adds write latency       |
| Event-driven invalidation | Use messaging or change data capture to invalidate/update cache | Scales when multiple services or processes modify the DB |

## References and further reading

* [Redis documentation](https://redis.io/documentation)
* [Cache-aside pattern overview (Martin Fowler)](https://martinfowler.com/bliki/CacheAside.html)
* \[Designing Data-Intensive Applications (Book) — caching patterns]

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/system-design-for-beginners/module/3ee9409c-c2ff-4102-9a76-af9840dc6e23/lesson/1282acaf-ea40-49df-a44a-df97a78d22ac" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/system-design-for-beginners/module/3ee9409c-c2ff-4102-9a76-af9840dc6e23/lesson/f85b3eb5-e4cc-4bf6-83a6-e89fae919f4f" />
</CardGroup>
