通过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引入多级缓存的包:
Install-Package Oxygen-MultilevelCache
接着我们需要注入两个具体的多级缓存实现,这里我们的一级缓存采用.netcore自带的memcache,二级缓存我们选用dapr的statemanager来实现,当然这两种实现你都可以替换成任意其他你熟知的缓存实现,并不影响最终效果。代码如下:
一级缓存实现:
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; } }
二级缓存实现:
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启动它:
builder.Services.AddMemoryCache(); builder.Services.InjectionCached<L1Cache, L2Cache>(); //...... var app = builder.Build(); app.UseCached(); //...... await app.RunAsync();
最后我们在AccountQueryService.cs里对GetMockAccount添加对应的缓存注解:
[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