COMPUTER ENGINEER

Jump to examples
Blog
Next.js / ASP.NET Core / SQL6 min study
32/ 41

Performance and caching

Cache layers: from the browser to Redis

The same data can be cached in five places. Which one when, and how is it invalidated?

UnderstandStudy an examplePractise

Understand the concept

There are many caching opportunities along a request’s path. The browser cache keeps static files and permitted responses on the user’s device. A CDN or proxy cache keeps responses that are identical for everyone at the edge. The Next.js data cache stores server-side fetch results with lifetimes and tags. On the API side an in-memory cache (IMemoryCache) works on one server, while a distributed cache such as Redis is shared by all servers. Finally the database has its own buffer pool.

The most common pattern is cache-aside: check the cache, on a miss fetch from the source and write to the cache. Key design is critical: everything that changes the response, such as language, filters and page, must be in the key; otherwise a Turkish request gets English data. In this project the Redis key includes language, filters and a ‘cache generation’.

The hard part is not caching but invalidating. A lifetime (TTL) is simple but stale for a while. Event-based invalidation (deleting the key or bumping the generation when a record changes) is fresh but every write path must do it. When the cache is unreachable the app must not fail; it falls back to the database.

WHEN TO USE IT

A cache in the right layer cuts database load and response time many times over.

COMMON PITFALL

Forgetting to put a response-affecting parameter (language, user, page) in the cache key.

LIVE ANIMATION

A letter’s journey through the city

Think of a request as a letter and the server as a city. Pick a scenario, press play and watch which gates the letter passes and where it gets stopped.

CLIENTEDGEWEB SERVERAPI · ASP.NET COREDATABrowserThe user’s screenNetworkDNS · TCP · TLSReverse proxyTLS termination, compressionNext.js serverSSR and route handlersKestrelHTTP serverException handlerMiddlewareRoutingEndpoint selectionRate limiterMiddlewareAuthenticationWho you areAuthorizationWhat you may doModel bindingHTTP → C# + validationControllerEndpoint codeServiceBusiness rules (DI)RedisDistributed cacheEF CoreLINQ → SQLSQL ServerQuery plan, indexes
OUTBOUND →

Someone else opens the same post. The tunnel is already open, so it leaves quickly.

BrowserYour screen. It writes the request and finally turns the answer into a page.
1 / 9
01 / PRACTICE

One topic. Three levels of depth.

Illustrative example
var key = $"post:{locale}:{slug}";
var json = await cache.GetStringAsync(key, ct);
if (json is null)
{
    var post = await LoadFromDatabase(slug, locale, ct);
    await cache.SetStringAsync(key, Serialize(post),
        new() { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(2) }, ct);
    return post;
}
return Deserialize(json);

Cache-aside: cache first, otherwise database and write back.

This page connects to no real server or database. Code samples are illustrative for .NET 8, Next.js and SQL Server; timings are example values in the simulation, not measurements. Try samples only in your own development environment; never share real connection strings, tokens or passwords.

02 / YOUR TURN

Try it yourself first.

You fixed a post title in the admin panel but the blog list shows the old title for 2 more minutes. How do you make it update immediately, and in which layers?

Show the solution and explanation
Worked solution
1) API: kayıt sonrası Redis nesil numarasını artır (liste anahtarları geçersiz).
2) Next.js: revalidateTag("public-posts") ile veri önbelleğini temizle.
3) CDN’de HTML önbellekleniyorsa ilgili yolu purge et.

Each cache layer is invalidated separately. Clearing only one does not stop another from serving stale data.