Cache-Aside
1. The Problem
You've got an ASP.NET Core ProductService running in Azure.
A customer requests:
GET /products/123
Your API goes to the database, gets the product, and returns it.
Seems fine, right?
Now imagine the same product is requested thousands of times.
Every request goes all the way to the database, even though the product information hasn't changed.
The flow looks like this:
Customer | v ASP.NET Core API | v Database | v Product 123
The database is doing the same work again and again.
For frequently requested data, that's unnecessary.
You need a faster place to keep a temporary copy of data that is accessed often.
That's where a cache comes in.
2. What's Actually Going Wrong?
The problem isn't necessarily that your database is slow.
The problem is that you're repeatedly asking the database for the same data.
For example:
Product 123 Product 123 Product 123 Product 123 Product 123 ...
If Product 123 hasn't changed, why keep going to the database?
You can keep a copy of frequently accessed data in a distributed cache such as Azure Managed Redis.
Now the request can potentially be served like this:
Customer | v ASP.NET Core API | v Azure Managed Redis | v Product 123
But there is an important question:
What happens when Product 123 isn't in the cache?
That's where Cache-Aside comes in.
3. The Concept
Cache-Aside is a caching pattern where the application manages the cache.
The application follows a simple flow:
- Check the cache first.
- If the data is there, return it.
- If the data isn't there, query the database.
- Put the result into the cache.
- Return the result.
The basic flow
+------------------+
| Request |
+--------+---------+
|
v
+------------------+
| ASP.NET Core |
| API |
+--------+---------+
|
v
+------------------+
| Cache |
+--------+---------+
|
+------+------+
| |
HIT MISS
| |
v v
Return data Query database
|
v
Put data in cache
|
v
Return data
The important idea is:
The cache is not the source of truth.
The database remains the source of truth.
The cache is simply a faster copy of data that the application expects to access frequently.
4. How Do You Fix It?
Same flow as before, with the generic "Cache" now a real Azure Managed Redis instance sitting between ASP.NET Core API and the database.
Here's what each branch actually looks like:
Cache HIT
Suppose Product 123 is already in Redis.
The request comes in:
Request | v ASP.NET Core API | v Redis | v Product 123 found | v Return response
The database isn't touched.
This is where the cache provides its biggest benefit.
Cache MISS
Now suppose Product 456 isn't in Redis.
The application checks the cache and doesn't find it.
So it goes to the database:
Request | v ASP.NET Core API | v Redis | | MISS v Database | v Product 456 | +--------> Store in Redis | v Return response
The next request for Product 456 can now be served from Redis.
This is the essence of Cache-Aside.
The application decides when to read from the cache and when to go to the database.
It also decides when data should be added to or removed from the cache.
One important point
Don't think of Cache-Aside as:
“Put everything in Redis.”
That's not the goal.
You typically cache data that is:
- Frequently requested
- Relatively expensive to retrieve
- Reasonably stable
- Acceptable to serve from a cached copy for some period
For example, product catalog information may be a good candidate.
Highly volatile or strongly consistent data may require a different approach.
5. What About Updates?
This is where caching gets interesting.
Suppose the database contains:
Product 123 Price = ₹1,200
But Redis still contains:
Product 123 Price = ₹999
Now you have stale data.
So caching isn't simply about putting data into Redis.
You also need a strategy for deciding how long cached data should remain valid.
TTL
A common approach is a TTL (Time To Live).
For example:
Product 123
|
v
Cache for 10 minutes
|
v
Expires
|
v
Next request
|
v
Database
|
v
Fresh value goes back into cache
This gives you a simple rule:
“This cached value is allowed to live for 10 minutes.”
For data where stale values are unacceptable, the application can explicitly invalidate or update the cache when the underlying data changes.
For example:
Update Product
|
v
Database updated
|
v
Invalidate cache
|
v
Next request
|
v
Cache MISS
|
v
Read fresh value from database
|
v
Populate cache
The exact strategy depends on the business requirement.
The important question is:
“How stale can this data be?”
If the answer is “it must never be stale,” you need to think much more carefully about whether a simple Cache-Aside approach is appropriate.
6. Visualize It in Everyday Terms
Imagine a restaurant manager.
The official menu and prices are maintained in the main office.
But the manager keeps the prices of the most popular dishes on a small card at the counter.
Why?
Because customers ask about those dishes all the time.
So:
- Main office = Database
- Counter card = Cache
- Restaurant manager = Application
A customer asks:
“What's the price of the most popular dish?”
The manager checks the counter card first.
If the price is there, the manager gives the answer immediately.
That's a cache hit.
If the price isn't there, the manager goes to the main office, gets the latest price, puts it on the counter card, and gives the answer to the customer.
That's a cache miss.
The next customer asking the same question gets the answer from the card.
That's Cache-Aside.
And if the price changes in the main office, the manager needs to make sure the card doesn't continue showing the old price forever.
That's the stale data problem.
7. What Should You Remember?
Think about Cache-Aside as:
REQUEST
|
v
CHECK CACHE
/ \
HIT MISS
| |
v v
RETURN DATA DATABASE
|
v
PUT IN CACHE
|
v
RETURN DATA
The five things to remember:
- Check the cache first.
- On a hit, return the cached data.
- On a miss, get the data from the database.
- Put the retrieved data into the cache.
- The database remains the source of truth.
And don't forget the sixth point:
Cached data can become stale.
So every caching design needs an appropriate expiration, invalidation, or refresh strategy.
The simplest mental model is:
Cache-Aside means the application checks the cache first, falls back to the database on a miss, and populates the cache with what it found.
8. .NET + Azure Context
From a .NET engineer's perspective, the important mental model is not:
“How do I use Redis?”
It is:
“Where should I look first, what do I do when it's not there, and how do I keep the cached copy from becoming a problem?”