Devizur
All insightsEngineering

Redis and Hybrid Caching in .NET: Performance Without Losing Correctness

Where caching helps, where it creates stale-data risk, and how Redis plus ASP.NET Core caching patterns can support multi-instance applications.

Soud Al Raihan2 July 20263 min read
RequestHybrid CacheRedisPostgreSQL

History and context

Early web caching
Applications cached rendered pages and objects in process memory.
Distributed systems
Multiple server instances required shared cache state outside a single process.
Redis adoption
Redis became widely used for fast in-memory data structures, distributed caching and real-time coordination.
Current .NET
ASP.NET Core supports memory, distributed, output and HybridCache patterns; cache design still depends on freshness and failure semantics.

Why caching exists

Caching trades freshness complexity for less repeated work. It is most useful when data is expensive to obtain, read frequently and safe to serve according to a clear staleness policy.

Cache-aside architecture

RequestASP.NET CoreRedis CachePostgreSQL
On a cache miss, the application reads durable data and populates the cache.

Cache-aside in code

C#
var cached = await cache.GetStringAsync(key, cancellationToken);

if (cached is not null)
    return JsonSerializer.Deserialize<ProductDto>(cached);

var product = await repository.GetAsync(productId, cancellationToken);

await cache.SetStringAsync(
    key,
    JsonSerializer.Serialize(product),
    new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
    },
    cancellationToken);

return product;

HybridCache for two-level caching

ASP.NET Core's HybridCache library is designed to combine local and distributed caching while helping with common cache concerns such as stampede protection.

C#
var product = await hybridCache.GetOrCreateAsync(
    $"product:{productId}",
    async token => await repository.GetAsync(productId, token),
    cancellationToken: cancellationToken);

Invalidation is the architecture

The most important cache question is not how fast Redis is. It is what makes a cached value stop being trusted.

  • TTL expiration
  • Explicit eviction after writes
  • Versioned keys
  • Event-driven invalidation
  • Change-data-capture approaches for selected workloads

Design for Redis failure

A cache should not silently become the only copy of critical business data. For ordinary cache-aside scenarios, application behaviour should remain correct if the cache is unavailable, while protecting the database from a sudden thundering herd.

What not to cache casually

  • Unfinalised financial calculations with unclear invalidation
  • Authorisation decisions without a strong revocation policy
  • Inventory values where stale data can oversell
  • Large objects with low reuse

Business value and practical considerations

Pros

  • Lower database load
  • Lower read latency
  • Shared cache for scale-out
  • Useful short-lived state

Considerations

  • Staleness risk
  • Operational dependency
  • Invalidation complexity
  • Memory cost
SA
Soud Al RaihanPerformance engineering · Devizur

References

Primary documentation used for terminology and current platform guidance: