ASP.NET Core | Caching or Response caching in ASP.NET Core
Caching significantly improves the performance of an application by reducing the number of calls to actual data source. It also improves the scalability. Response caching is best suited for data that changes infrequently. Caching makes the copy of data and store it instead of generating data from original source.
Response caching headers control the response caching. ResponseCache
attribute sets these caching headers with additional properties.
In-memory caching
In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers using session affinity. Session affinity is also known as sticky sessions. Session affinity means that the requests from a client are always routed to the same server for processing.
Distributed Cache
Use a distributed cache to store data when the app is hosted in a cloud or server farm. The cache is shared across the servers that process requests. A client can submit a request that's handled by any server in the group if cached data for the client is available. ASP.NET Core works with SQL Server, Redis, and NCache distributed caches.
HybridCache
The HybridCache API bridges some gaps in the IDistributedCache and IMemoryCache APIs. HybridCache
is an abstract class wth a default implementation that handles most aspects of saving to cache and retrieving from cache.
Features
HybridCache
has the following features that the other APIs don't have:
A unified API for both in-process and out-of-process caching.
HybridCache
is designed to be a drop-in replacement for existingIDistributedCache
andIMemoryCache
usage, and it provides a simple API for adding new caching code. If the app has anIDistributedCache
implementation, theHybridCache
service uses it for secondary caching. This two-level caching strategy allowsHybridCache
to provide the speed of an in-memory cache and the durability of a distributed or persistent cache.Stampede protection.
Cache stampede happens when a frequently used cache entry is revoked, and too many requests try to repopulate the same cache entry at the same time.
HybridCache
combines concurrent operations, ensuring that all requests for a given response wait for the first request to populate the cache.Configurable serialization.
Serialization is configured as part of registering the service, with support for type-specific and generalized serializers via the
WithSerializer
andWithSerializerFactory
methods, chained from theAddHybridCache
call. By default, the service handlesstring
andbyte[]
internally, and usesSystem.Text.Json
for everything else. It can be configured for other types of serializers, such as protobuf or XML.
To see the relative simplicity of the HybridCache
API, compare code that uses it to code that uses IDistributedCache
. Here's an example of what using IDistributedCache
looks like:
public class SomeService(IDistributedCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
var bytes = await cache.GetAsync(key, token); // Try to get from cache.
SomeInformation info;
if (bytes is null)
{
// Cache miss; get the data from the real source.
info = await SomeExpensiveOperationAsync(name, id, token);
// Serialize and cache it.
bytes = SomeSerializer.Serialize(info);
await cache.SetAsync(key, bytes, token);
}
else
{
// Cache hit; deserialize it.
info = SomeSerializer.Deserialize<SomeInformation>(bytes);
}
return info;
}
// This is the work we're trying to cache.
private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
CancellationToken token = default)
{ /* ... */ }
}
That's a lot of work to get right each time, including things like serialization. And in the "cache miss" scenario, you could end up with multiple concurrent threads, all getting a cache miss, all fetching the underlying data, all serializing it, and all sending that data to the cache.
Here's equivalent code using HybridCache
:
public class SomeService(HybridCache cache)
{
public async Task<SomeInformation> GetSomeInformationAsync
(string name, int id, CancellationToken token = default)
{
return await cache.GetOrCreateAsync(
$"someinfo:{name}:{id}", // Unique key for this entry.
async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
token: token
);
}
}
The code is simpler and the library provides stampede protection and other features that IDistributedCache
doesn't.
Comments
Post a Comment