About me

The author blog | start

Caching basics

Caching can significantly improve application performance and scalability by reducing the effort required to generate content. Caching works best for data that doesn’t change often and is expensive to generate. With caching, it is possible to make a much faster copy of the data returned from the data source. Applications should be written and tested so that they never rely on cached data.

ASP.NET Core supports multiple different caches. The simplest cache is based on IMemoryCache. IMemoryCache represents the cache stored in the memory of the Web server. Applications running on a server farm (multiple servers) should ensure that sessions are stuck while using in-memory caches. Sticky sessions ensure that subsequent requests from clients are sent to the same server.

An in-memory cache can store any object. The distributed cache interface is limited to byte[]. In-memory and distributed caches use cached items as key-value pairs.

Cache guide

  • Code should always have fallback options to retrieve data, rather than relying on available cache values.
  • Caches use rare resource memory to limit cache growth:
    • Do not use external inputs as cache keys.
    • Use expiration to limit cache growth.
    • Limit the cache Size using SetSize, Size, and SizeLimit]. The ASP.NET Core runtime does not limit the cache size based on memory pressure. Developers need to limit the cache size.

use

DI injection

Create a NetCore console project to demonstrate the caching project.

The console project has only one initialized program.cs file. Each step of coding projects based on NetCore is to create a basic template using dependency injection.

nuget install Microsoft.Extensions.Hosting
Copy the code
public static class Program { static async void Main(string[] args) { var builder = new HostBuilder().ConfigureServices((context, service) => { }); await builder.RunConsoleAsync(); }}Copy the code

Into the cache service, console library need to download the Microsoft Extensions. Caching. The Memory

nuget install Microsoft.Extensions.Caching.Memory
Copy the code
public static class Program { static async void Main(string[] args) { var builder = new HostBuilder().ConfigureServices((context, service) => { service.AddMemoryCache(); service.AddScoped<CacheService>(); // The actual test service service.addhostedService <BackgroundJob>(); }); await builder.RunConsoleAsync(); }}Copy the code

Background services

public class BackgroundJob : IHostedService { private readonly CacheService _cacheService; public BackgroundJob(CacheService cacheService) { _cacheService = cacheService; } public Task StartAsync(CancellationToken cancellationToken) { _cacheService.Action(); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; }}Copy the code

Summary of MemoryCache usage

IMemoryCache is automatically injected through the constructor

public class CacheService { private readonly IMemoryCache _memoryCache; public CacheService(IMemoryCache memoryCache) { _memoryCache = memoryCache; }}Copy the code

The most basic use

The Set method sets the cache based on the Key. The default cache does not expire

The Get method fetches the cache based on the Key

/// </summary> public void BaseCache() {string cacheKey = "timestamp"; // </summary> public void BaseCache() {string cacheKey = "timestamp"; //set cache _memoryCache.Set(cacheKey, DateTime.Now.ToString()); //get cache Console.WriteLine(_memoryCache.Get(cacheKey)); }Copy the code

IMemoryCache provides some good syntax candy for developers to use, see the documentation below

/// </summary> public void ActionUse() {// Scenario - If the cache exists, remove it. If the cache does not exist, write // primitive string cacheKey = "timestamp"; if (_memoryCache.Get(cacheKey) ! = null) { _memoryCache.Set(cacheKey, DateTime.Now.ToString()); } else { Console.WriteLine(_memoryCache.Get(cacheKey)); Var dataCacheValue = _memoryCache.getorCreate (cacheKey, entry => {return datetime.now.tostring (); }); Console.WriteLine(dataCacheValue); _memorycache. Remove(cacheKey); _memoryCache.TryGetValue(cacheKey, out string cacheValue); Console.WriteLine(cacheValue); }Copy the code

Cache expiration policy

There are two common ways to set the cache

  1. Absolute maturity (specified to expire at a fixed point in time)
  2. Slide expiration (expires if not hit for a length of time)
  3. Combination expiration (absolute expiration + sliding expiration)

Absolute maturity

Expiration Policy expires in 5 seconds

//set absolute cache
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), TimeSpan.FromSeconds(5));

//get absolute cache
for (int i = 0; i < 6; i++)
{
    Console.WriteLine(_memoryCache.Get(cacheKey));
    Thread.Sleep(1000);
}
Copy the code

Sliding due

Expiration policy Sliding expiration time of 2 seconds. If there is access within 2 seconds, the expiration time is delayed. When there is no access within the 2-second interval, the cache expires

//set slibing cache
string cacheSlibingKey = "slibingKey";
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.SlidingExpiration = TimeSpan.FromSeconds(2);

_memoryCache.Set(cacheSlibingKey, DateTime.Now.ToString(), options);

//get slibing cache
for (int i = 0; i < 2; i++)
{
    Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
    Thread.Sleep(1000);
}
for (int i = 0; i < 2; i++)
{
    Thread.Sleep(2000);
    Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
}
Copy the code

Combination of overdue

Expiry policies

6 seconds absolute expiration +2 seconds sliding expiration

Any of these caches will be invalidated

string cacheCombineKey = "combineKey";
MemoryCacheEntryOptions combineOptions = new MemoryCacheEntryOptions();
combineOptions.SlidingExpiration = TimeSpan.FromSeconds(2);
combineOptions.AbsoluteExpiration = DateTime.Now.AddSeconds(6);

_memoryCache.Set(cacheCombineKey, DateTime.Now.ToString(), combineOptions);

//get slibing cache
for (int i = 0; i < 2; i++)
{
    Console.WriteLine(_memoryCache.Get(cacheCombineKey));
    Thread.Sleep(1000);
}

for (int i = 0; i < 6; i++)
{
    Thread.Sleep(2000);
    Console.WriteLine(i+"|" + _memoryCache.Get(cacheCombineKey));
}

Console.WriteLine("------------combineKey End----------------");
Copy the code

Caches state change events

When the cache is updated or deleted, a callback event is triggered to record the cache changes.

/// <summary> /// cache status change callback /// </summary> public void CacheStateCallback() {MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); options.AbsoluteExpiration = DateTime.Now.AddSeconds(3 ); options.RegisterPostEvictionCallback(MyCallback, this); //show callback console string cacheKey = "absoluteKey"; _memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); Thread.Sleep(500); _memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); _memoryCache.Remove(cacheKey); } private static void MyCallback(object key, object value, EvictionReason reason, object state) { var message = $"Cache entry state change:{key} {value} {reason} {state}"; ((CacheService)state)._memoryCache.Set("callbackMessage", message); Console.WriteLine(message); }Copy the code

Cache dependency policy

Set A cache A Set A cache B, depending on cache A if cache A fails, cache B fails

</ / </summary> public void CacheDependencyPolicy() {string DependentCTS = "DependentCTS"; string cacheKeyParent = "CacheKeys.Parent"; string cacheKeyChild = "CacheKeys.Child"; var cts = new CancellationTokenSource(); _memoryCache.Set(DependentCTS, cts); Using (var Entry = _memoryCache.createEntry (cacheKeyParent)) {// The current key Value entry.Value = "parent" + DateTime.Now; / / the current key corresponding to the callback event entry. RegisterPostEvictionCallback (MyCallback, this); _memoryCache.Set(cacheKeyChild, "child" + datetime. Now, new CancellationChangeToken(cts.token)); } string ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent); string ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild); string callBackMsg = _memoryCache.Get<string>("callbackMessage"); Console.WriteLine(" First fetch "); Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg); ParentKey _memoryCache.Get<CancellationTokenSource>(DependentCTS).cancel (); Thread.Sleep(1000); ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent); ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild); callBackMsg = _memoryCache.Get<string>("callbackMessage"); Console.WriteLine(" Second fetch "); Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg); }Copy the code

The resources

Cache memory in AspNetCore

. MemoryCache for NetCore cache

Asp.Net Core easy to learn – in. Net Core uses caching and configure dependency policies

[Embrace.net Core Series: MemoryCache Expiration]