通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存
很久没有更新dapr系列了。今天带来的是一个小的组件集成,通过多级缓存框架来实现对服务的缓存保护,依旧是一个简易的演示以及对其设计原理思路的讲解,欢迎大家转发留言和star
目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统
二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
五、通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
六、通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
七、通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
八、通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
九、通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权 && 百度版Oauth2
十、通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定
十一、通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容
十二、通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格
十三、通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署
十四、通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧
十五、通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现
十六、通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护
十七、通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载
十八、通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存
十九、通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式
二十、通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址
今天我们演示一下,在创建订单的时候,订单服务会通过rpc拉取用户服务获取一个随机用户来模拟下订单。这个随机用户的接口接下来我会尝试使用多级缓存来保护。首先我们需要在AccountService的Infrastructure层通过nuget引入多级缓存的包:
1 | Install-Package Oxygen-MultilevelCache |
接着我们需要注入两个具体的多级缓存实现,这里我们的一级缓存采用.netcore自带的memcache,二级缓存我们选用dapr的statemanager来实现,当然这两种实现你都可以替换成任意其他你熟知的缓存实现,并不影响最终效果。代码如下:
一级缓存实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class L1Cache : IL1CacheServiceFactory { private readonly IMemoryCache memoryCache; public L1Cache(IMemoryCache memoryCache) { this .memoryCache = memoryCache; } public T Get<T>( string key) { Console.WriteLine($ "L1缓存被调用,KEY={key},value{(memoryCache.Get<T>(key) == null ? " 不存在 " : " 存在 ")}" ); return memoryCache.Get<T>(key); } public bool Set<T>( string key, T value, int expireTimeSecond = 0) { return memoryCache.Set(key, value, DateTimeOffset.Now.AddSeconds(expireTimeSecond)) != null ; } } |
二级缓存实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public class L2Cache : IL2CacheServiceFactory { private readonly IStateManager stateManager; public L2Cache(IStateManager stateManager) { this .stateManager = stateManager; } public async Task<T> GetAsync<T>( string key) { var cache = await stateManager.GetState( new L2CacheStore(key), typeof (T)); Console.WriteLine($ "L2缓存被调用,KEY={key},value{(cache == null ? " 不存在 " : " 存在 ")}" ); if (cache != null ) return (T)cache; return default (T); } public async Task< bool > SetAsync<T>( string key, T value, int expireTimeSecond = 0) { var resp = await stateManager.SetState( new L2CacheStore(key, value, expireTimeSecond)); return resp != null ; } } internal class L2CacheStore : StateStore { public L2CacheStore( string key, object data, int expireTimeSecond = 0) { Key = $ "DarpEshopL2CacheStore_{key}" ; this .Data = data; this .TtlInSeconds = expireTimeSecond; } public L2CacheStore( string key) { Key = $ "DarpEshopL2CacheStore_{key}" ; } public override string Key { get ; set ; } public override object Data { get ; set ; } } |
接着我们将这两个实现注入到我们的webapplication里并在middleware里通过use启动它:
1 2 3 4 5 6 7 | builder.Services.AddMemoryCache(); builder.Services.InjectionCached<L1Cache, L2Cache>(); //...... var app = builder.Build(); app.UseCached(); //...... await app.RunAsync(); |
最后我们在AccountQueryService.cs里对GetMockAccount添加对应的缓存注解:
1 2 3 4 5 6 | [SystemCached] public async Task<ApiResult> GetMockAccount() { Console.WriteLine( "GetMockAccount被调用" ); //...... } |
*默认注解参数为int expireSecond = 60, int timeOutMillisecond = 5000, SystemCachedType cachedType = SystemCachedType.Method。其中expireSecond代表你想要的缓存的时间,单位为秒,timeOutMillisecond是指在框架尝试请求二级缓存时的超时等待时长,单位毫秒。cachedType代表缓存类别,SystemCachedType.Method代表仅使用方法作为缓存key,SystemCachedType.MethodAndParams代表会根据方法名+参数来实现更加细化的缓存key
最后启动我们的项目,现在通过postman来访问这个接口,打印日志如下:
可以看到首先会尝试访问L1缓存实现,如果没有找到对应的key会尝试访问L2缓存实现,最终会访问原始服务并将缓存结果进行多级缓存,所以当再次请求这个接口时将不再产生对原始服务的调用:
接下来我们停止掉这个pod,让k8s重启一个新的pod来模拟L1缓存失效时的情况,可以看到首次调用时L2缓存被调用并且会重新覆写到L1,后面再次调用都会命中L1的缓存:
演示很简单,大家可以下载最新版本的代码rebuild通过调用创建订单并log accountservice来观察多级缓存是否起作用。
下面来讲解一下多级缓存的实现思路:
从流程图里看起来很简单,其实就是一个AOP原理的实现,通过systemcached注解为对应的方法体创建一个proxy代理并注入到IOC容器中。当方法被调用时被proxy拦截到请求后依次串行调用L1、L2、realservice实现。
具体有兴趣的朋友可以看看github上的代码:https://github.com/sd797994/Oxygen-MultilevelCache
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」