下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
下麵是一個標準的IDistributedCache
用例:
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)
{ /* ... */ }
}
在這個用例中 每次都要做很多事情,包括序列化/反序列化。如果緩存不存在/未命中,可能會有多個併發線程獲取基礎數據並序列化數據,並將所有數據推送到緩存中間件中,我們看到這裡 分散式緩存使用上就沒有IMemoryCache
那麼性能高效, 為此.NET團隊在NET9中 添加了 HybridCache
解決這個痛點,
原理還是簡單,使用本地的IMemoryCache
給IDistributedCache
包裝一層,提供一個二級緩存包裝的概念.
下麵簡單引用並註冊一下服務:
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />
services.AddMemoryCache();
services.AddDistributedMemoryCache();//分散式緩存簡單測試用的記憶體緩存,可以是Garnet,Redis等~
services.AddHybridCache(options =>
{
//options.MaximumPayloadBytes = 1*1024*1024 //預設超過1M的數據不會提供二級緩存,避免應用伺服器記憶體負擔
options.DefaultEntryOptions = new HybridCacheEntryOptions{
Expiration = TimeSpan.FromSeconds(5 * 60),//設置一個分散式緩存預設過期時間
LocalCacheExpiration = TimeSpan.FromSeconds(5 * 60 - 1)//二級緩存預設過期時間,比前者短就行.或開發者可以接受的範圍
};
});
minimal api中的簡單用例:
/// <summary>
/// 模擬的緩存數據類型
/// </summary>
public record CacheData(DateTime? DateTime);
//NET8中的IDistributedCache
x.MapGet("/cached-in-distribute", async (IDistributedCache distributedCache) =>
{
if (await distributedCache.GetStringAsync("$cached-in-distribute") is null)
{
var data = System.Text.Json.JsonSerializer.Serialize(new CacheData(DateTime.Now));
await distributedCache.SetStringAsync("$cached-in-distribute", data, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10d)
});
}
var fromCacheData = System.Text.Json.JsonSerializer.Deserialize<CacheData>(
await distributedCache.GetStringAsync("$cached-in-distribute") ?? throw new Exception());
return Results.Content($"{fromCacheData?.DateTime}-{DateTime.Now}");
});
//NET9 HybridCache,避免分散式緩存的強制轉換
x.MapGet("/cached-in-hybrid", async (HybridCache hybridCache) =>
{
var cachedDate = await hybridCache.GetOrCreateAsync($"$cached-in-hybrid", async cancel =>
{
return await ValueTask.FromResult(new CacheData(DateTime.Now));
}, options: new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromSeconds(10d),//便於驗證,設直10秒過期
LocalCacheExpiration = TimeSpan.FromSeconds(10d),
});
return Results.Content($"緩存的數據:{cachedDate.DateTime}");
});
HybridCache
通過本地的二級緩存避免了頻繁的與分散式緩存伺服器的交互以及成本高昂的類型轉換(如果數據結構複雜龐大更甚),性能瞬間又提升了.
另外HybridCache
是一個抽象類,微軟預設的實現是二級到記憶體緩存,如果你有興趣甚至可以無限封裝擴展到其他的緩存中 比如你自己的YourHybridCache
services.TryAddSingleton<HybridCache, YourHybridCache>();
最後Microsoft.Extensions.Caching.Hybrid
相容.NET Framework 4.7.2
and .NET Standard 2.0
這個也可以點個贊,對老系統升級比較友好!
更多信息:
https://learn.microsoft.com/en-us/aspnet/core/performance/caching/hybrid?view=aspnetcore-9.0
用例代碼:
https://github.com/vipwan/Biwen.QuickApi/blob/net9/Biwen.QuickApi.DemoWeb/~DemoModular.cs