Caching is essential for optimizing application performance by lowering data retrieval latency and reducing the number of database or API calls. In .NET 9.0, Microsoft has introduced improved caching strategies, including Hybrid Caching, which merges the advantages of in-memory and distributed caching. This blog delves into Hybrid Caching in .NET 9.0, covering its benefits, implementation, and best practices.
What is Hybrid Caching?
Hybrid Caching is a strategy that combines in-memory and distributed caching to optimize performance and scalability. It leverages the speed of in-memory caching while maintaining persistence and scalability through distributed caching solutions like Redis or SQL Server.
Advantages of Hybrid Caching
- Enhanced Performance: Stores frequently accessed data in memory, minimizing response time.
- Scalability: Ensures data consistency across multiple servers through distributed caching.
- Increased Reliability: Implements failover mechanisms to prevent data loss during system failures.
- Cost Efficiency: Reduces dependence on costly database queries, optimizing resource usage.
- Prevention of Cache Stampede: Efficiently manages cache misses to avoid multiple simultaneous database requests.
Cache Stampede. Issue and Solution
What is Cache Stampede?
A cache stampede occurs when multiple concurrent requests attempt to access the same data from the cache but encounter a cache miss. As a result, all requests simultaneously query the original data source, potentially overwhelming it with excessive load.
How Hybrid Caching Prevents Cache Stampede?
Hybrid Caching in .NET 9.0 helps mitigate cache stampede through:
- Locking Mechanisms: Ensuring only one request retrieves data from the source while others wait.
- Stale Data Serving: Temporarily providing slightly expired data while fresh data is fetched in the background.
- Preemptive Refreshing: Updating cache entries before expiration to minimize sudden cache misses.
Implementing Hybrid Caching in .NET 9.0
The source code can be downloaded from GitHub
Hybrid Caching in .NET 9.0 can be implemented using Microsoft.Extensions.Caching.Hybrid is currently an experimental package that is under preview. Below is a step-by-step guide to integrating it into your application:
1. Install the Required Package
Begin by installing the required NuGet package:
Microsoft.Extensions.Caching.StackExchangeRedis
Microsoft.Extensions.Caching.Hybrid
![Browse]()
Note: I installed the Redis from this gitHub
2. Configure Caching Service
Modify the Program.cs file to configure Hybrid Caching.
using HybridCachingIndotNET9._0;
using Microsoft.Extensions.Caching.Hybrid;
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();
builder.Services.AddSingleton<HybridCacheService>();
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "your redis connection string";
options.InstanceName = "HybridCache";
});
#pragma warning disable EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
builder.Services.AddHybridCache(options =>
{
// Maximum size of cached items
options.MaximumPayloadBytes = 1024 * 1024 * 10; // 10MB
options.MaximumKeyLength = 512;
// Default timeouts
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(30),
LocalCacheExpiration = TimeSpan.FromMinutes(30)
};
});
#pragma warning restore EXTEXP0018 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.MapScalarApiReference();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
3. Implement Hybrid Caching Logic
using Microsoft.Extensions.Caching.Hybrid;
namespace HybridCachingIndotNET9._0
{
public class HybridCacheService
{
private readonly HybridCache _hybridCache;
private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(30);
public HybridCacheService(HybridCache hybridCache)
{
_hybridCache = hybridCache;
}
public async Task<string> GetCachedDataAsync(
string key,
CancellationToken ct)
{
var product = await _hybridCache.GetOrCreateAsync(
$"product-{key}",
async token =>
{
return await FetchData(key, token);
},
cancellationToken: ct
);
return product;
}
private async Task<string> FetchData(string key, CancellationToken ct)
{
// Simulate a long-running operation
await Task.Delay(5000, ct);
return $"Product {key}";
}
}
}
4. Inject and Use HybridCachingService
Register the HybridCachingService in the Program.cs
builder.Services.AddSingleton<HybridCacheService>();
Use this service in the Controller.
using Microsoft.AspNetCore.Mvc;
namespace HybridCachingIndotNET9._0.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DataController : ControllerBase
{
private readonly HybridCacheService _hybridCacheService;
public DataController(HybridCacheService hybridCacheService)
{
_hybridCacheService = hybridCacheService;
}
[HttpGet("get-data")]
public async Task<IActionResult> Get(CancellationToken ct)
{
var data = await _hybridCacheService.GetCachedDataAsync("test", ct);
return Ok(data);
}
}
}
5. Execute the code and see the result
![Execute]()
Effective Hybrid Caching Practices
- Cache Expiration Policy: Apply suitable expiration rules to avoid outdated data.
- Eviction Strategy: Use eviction methods like LRU (Least Recently Used) for optimal cache management.
- Consistency Management: Maintain synchronization between in-memory and distributed caches.
- Performance Monitoring: Leverage logging tools to monitor cache performance and track hit/miss rates.
- Cache Stampede Prevention: Implement locking techniques and proactive refresh methods to prevent unnecessary database queries.
Ina addition to this, there is a concept, Tags, which help categorize or group cache entries, making cache invalidation, eviction, and management more efficient, particularly in a hybrid setup. Please refer the Microsoft learning for more details.
When Redis is added as a caching solution in a hybrid setup, it usually serves as the L2 (Level 2) cache by default.
How Redis Becomes L2 in Hybrid Caching?
In a hybrid caching setup, Redis is often used to manage larger datasets that need to be persistent and accessible across multiple application instances. As a distributed, high-performance caching solution, Redis operates outside of the application's memory, typically storing data in a separate service, which classifies it as a Level 2 (L2) cache.
Data Flow Process
- L1 Cache (Local Cache): The application first checks the local cache (such as MemoryCache) for the required data. This is quick since the data is stored directly in the application's memory.
- L2 Cache (Redis): If the data is not in the local cache, the application queries Redis (L2). Redis is more persistent, can store larger datasets, and is accessible across multiple application instances.
- Database Fallback: If the data is not found in either the L1 or L2 cache, the application falls back to the primary data store (e.g., a database).
Example Workflow in Hybrid Caching
- Check L1 Cache (in-memory): If the data is found, it is returned.
- Check L2 Cache (Redis): If the data is not in L1, Redis is queried. If found, the data is cached in L1 for future access.
- Fallback to Database: If the data is missing in both L1 and L2, the database is queried, and the data is then cached in both L1 and L2 for subsequent requests.
Conclusion
Hybrid Caching in .NET 9.0 provides a powerful solution for improving application performance, minimizing latency, and optimizing resource usage. With Microsoft.Extensions.Caching.Hybrid developers can achieve enhanced speed and scalability in a more efficient manner. By following best practices for cache management, applications become more resilient and performant. Moreover, Hybrid Caching includes built-in features to prevent cache stampede, ensuring a stable and effective caching strategy for contemporary applications.
Happy Coding!