NET9 提供HybridCache解决分布式缓存中存在的远程链接&序列化带来的性能问题

下面是一个标准的IDistributedCache用例:

csharp 复制代码
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解决这个痛点,

原理还是简单,使用本地的IMemoryCacheIDistributedCache包装一层提供一个二级缓存包装的概念.

下面简单引用并注册一下服务:

xml 复制代码
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />
csharp 复制代码
services.AddMemoryCache();
services.AddDistributedMemoryCache();//分布式缓存这里默认本地内存缓存,可以是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中的简单用例:

csharp 复制代码
/// <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

csharp 复制代码
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

相关推荐
万雅虎2 个月前
使用 `Roslyn` 分析器和修复器 对异步方法规范化返回Async结尾
netcore·roslyn·csharp·sg
万雅虎3 个月前
使用Kiota工具生成WebApi的代理类,以及接口调用的简单体验
webapi·aspnetcore·kiota
ggtc3 个月前
前后端分离项目,后期前端身份验证的麻烦
前后端分离·身份认证·netcore
万雅虎4 个月前
使用 Alba 对 AspnetCore项目进行测试
单元测试·aspnetcore
ggtc5 个月前
WebRTC入门
webrtc·netcore
万雅虎5 个月前
NET8中增加的简单适用的DI扩展库Microsoft.Extensions.DependencyInjection.AutoActivation
netcore·aspnetcore
ggtc6 个月前
基于WebSocket的modbus通信(二)- 客户端
modbustcp·websocket·netcore
ggtc6 个月前
基于WebSocket的modbus通信(一)- 服务器
websocket·c#·modbus·netcore
程序设计实验室6 个月前
Asp-Net-Core开发笔记:使用原生的接口限流功能
c#·aspnetcore