上一篇讲到了,Core的内置缓存:IMemoryCache,以及缓存的基础概念。本篇会进行一些概念上的补充。web
本篇咱们记录的内容是怎么在Core中使用Redis 和 SQL Server 实现分布式缓存。数据库
分布式缓存描述:api
分布式缓存重点是在分布式上,相信你们接触过的分布式有不少中,像分布式开发,分布式部署,分布式锁、事物、系统 等有不少。使咱们对分布式自己就有一个很明确的认识,分布式就是有多个应用程序组成,可能分布在不一样的服务器上,最终都是在为web端提供服务。缓存
分布式缓存有如下几点优势:服务器
(1)全部的Web服务器上的缓存数据都是相同的,不会由于应用程序不一样,服务器的不一样致使缓存数据的不同。架构
(2)缓存的是独立的不受Web服务器的从新启动或被删除添加的影响,也就是说这些Web的改变不到致使缓存数据的改变。并发
传统的单体应用架构由于用户的访问量的不高,缓存的存在大多数都是存储用户的信息,以及一些页面,大多数的操做都是直接和DB进行读写交互,这种架构简单,也称为简单架构,异步
传统的OA项目好比ERP,SCM,CRM等系统由于用户量不大也是由于大多数公司业务的缘由,单体应用架构仍是很经常使用的架构,可是有些系统随着用户量的增长,业务的扩张扩展,致使DB的瓶颈的出现。async
如下我所了解到的关于这种状况的处理有如下两种分布式
(1):当用户访问量不大,可是读写的数据量很大的时候,咱们通常采起的是,对DB进行读写分离、一主多从、对硬件进行升级的方式来解决DB瓶颈的问题。
这样的缺点也一样纯在:
一、用户量大的时候怎么办?,
二、对于性能的提高有限,
三、性价比不高。提高一点性能就须要花费不少代价,(打个比方,如今的I/O吞吐量是0.9的须要提高到1.0,咱们在增长机器配置的状况下这个价格确实很可观的)
(2):当用户访问量也增长的时候,咱们就须要引入缓存了来解决了,一张图描述缓存的大体的做用。
缓存主要针对的是不常常发生改变的而且访问量很大的数据,DB数据库能够理解为只做为数据固化的或者只用来读取常常发生改变的数据,上图中我没有画SET的操做,就是想特地说明一下,缓存的存在能够做为一个临时的数据库,咱们能够经过定时的任务的方式去同步缓存和数据库中的数据,这样作的好处是能够转移数据库的压力到缓存中。
缓存的出现解决了数据库压力的问题,可是当如下状况发生的时候,缓存就不在起到做用了,缓存穿透、缓存击穿、缓存雪崩这三种状况。
缓存穿透:咱们的程序中用缓存的时候通常采起的是先去缓存中查询咱们想要的缓存数据,若是缓存中不存在咱们想要的数据的话,缓存就失去了作用(缓存失效)咱们就是须要伸手向DB库去要数据,这个时候这种动做过多数据库就崩溃了,这种状况须要咱们去预防了。好比说:咱们向缓存获取一个用户信息,可是故意去输入一个缓存中不存在的用户信息,这样就避过了缓存,把压力从新转移到数据上面了。对于这种问题咱们能够采起,把第一次访问的数据进行缓存,由于缓存查不到用户信息,数据库也查询不到用户信息,这个时候避免重复的访问咱们把这个请求缓存起来,把压力从新转向缓存中,有人会有疑问了,当访问的参数有上万个都是不重复的参数而且都是能够躲避缓存的怎么办,咱们一样把数据存起来设置一个较短过时时间清理缓存。
缓存击穿:事情是这样的,对于一些设置了过时时间的缓存KEY,在过时的时候,程序被高并发的访问了(缓存失效),这个时候使用互斥锁来解决问题,
互斥锁原理:通俗的描述就是,一万个用户访问了,可是只有一个用户能够拿到访问数据库的权限,当这个用户拿到这个权限以后从新建立缓存,这个时候剩下的访问者由于没有拿到权限,就原地等待着去访问缓存。
永不过时:有人就会想了,我不设置过时时间不就好了吗?能够,可是这样作也是有缺点的,咱们须要按期的取更新缓存,这个时候缓存中的数据比较延迟。
缓存雪崩:是指多种缓存设置了同一时间过时,这个时候大批量的数据访问来了,(缓存失效)数据库DB的压力又上来了。解决方法在设置过时时间的时候在过时时间的基础上增长一个随机数尽量的保证缓存不会大面积的同事失效。
在项目中引用:using Microsoft.Extensions.Caching.Distributed; 使用IDistributedCache
IDistributedCache接口包含同步和异步方法。 接口容许在分布式缓存实现中添加、检索和删除项。 IDistributedCache接口包含如下方法:
Get、 GetAsync
采用字符串键并以byte[]形式检索缓存项(若是在缓存中找到)。
Set、SetAsync
使用字符串键向缓存添加项byte[]形式)。
Refresh、RefreshAsync
根据键刷新缓存中的项,并重置其可调过时超时值(若是有)。
Remove、RemoveAsync
根据键删除缓存项。
如下是个人代码封装DistributedCache类名:主要针对IDistributedCache中非异步方法,异步只写了一个简单的例子:
一、Get()获取缓存
/// <summary> /// 获取缓存 /// </summary> /// <param name="key"></param> /// <returns></returns> public object Get(string key) { string ReturnStr = ""; if (!string.IsNullOrEmpty(key)) { if (Exists(key)) { ReturnStr = Encoding.UTF8.GetString(_cache.Get(key)); } } return ReturnStr; }
/// <summary> /// 使用异步获取缓存信息 /// </summary> /// <param name="key"></param> /// <returns></returns> public async Task<object> GetAsync(string key) { string ReturnString = null; var value = await _cache.GetAsync(key); if (value != null) { ReturnString = Encoding.UTF8.GetString(value); } return ReturnString; }
3、Set()设置或添加缓存
/// <summary> /// 添加缓存 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Add(string key, object value) { byte[] val = null; if (value.ToString() != "") { val = Encoding.UTF8.GetBytes(value.ToString()); } DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); //设置绝对过时时间 两种写法 options.AbsoluteExpiration = DateTime.Now.AddMinutes(30); // options.SetAbsoluteExpiration(DateTime.Now.AddMinutes(30)); //设置滑动过时时间 两种写法 options.SlidingExpiration = TimeSpan.FromSeconds(30); //options.SetSlidingExpiration(TimeSpan.FromSeconds(30)); //添加缓存 _cache.Set(key, val, options); //刷新缓存 _cache.Refresh(key); return Exists(key); }
四、Remove()删除缓存
/// <summary> /// 删除缓存 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Remove(string key) { bool ReturnBool = false; if (key != "" || key != null) { _cache.Remove(key); if (Exists(key) == false) { ReturnBool = true; } } return ReturnBool; }
5、修改缓存
/// <summary> /// 修改缓存 /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> public bool Modify(string key, object value) { bool ReturnBool = false; if (key != "" || key != null) { if (Remove(key)) { ReturnBool = Add(key, value.ToString()); } } return ReturnBool; }
6、验证缓存是否存在
/// <summary> /// 验证是否存在 /// </summary> /// <param name="key"></param> /// <returns></returns> public bool Exists(string key) { bool ReturnBool = true; byte[] val = _cache.Get(key); if (val == null || val.Length == 0) { ReturnBool = false; } return ReturnBool; }
1、首先安装Redis缓存:这个网上找个下载安装就行
2、而后下载安装:客户端工具:RedisDesktopManager(方便管理)
3、在咱们的项目Nuget中 引用 Microsoft.Extensions.Caching.Redis
4、在项目启动Setup.cs中注册:Redis服务:代码以下
public void ConfigureServices(IServiceCollection services) { //将Redis分布式缓存服务添加到服务中 services.AddDistributedRedisCache(options => { //用于链接Redis的配置 Configuration.GetConnectionString("RedisConnectionString")读取配置信息的串 options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString"); //Redis实例名RedisDistributedCache options.InstanceName = "RedisDistributedCache"; }); services.AddMvc(); }
五、我是用CoreAPI来写的 控制器中代码以下:
1)先实例对象
private DistributedCache _Cache; /// <summary> /// 构造注入 /// </summary> /// <param name="Cache"></param> public ValuesController(IDistributedCache Cache) { _Cache = new DistributedCache(Cache); }
2)调用DistributedCache 类中的方法 代码以下:
[HttpGet("{id}")] public string Get(int id) { //添加 bool booladd = _Cache.Add("id", "sssss"); //验证 bool boolExists = _Cache.Exists("id"); //获取 object obj = _Cache.Get("id"); //删除 bool boolRemove = _Cache.Remove("id"); //修改 bool boolModify = _Cache.Modify("id", "ssssssss"); return obj.ToString(); }
OK 结束,最后吐槽一下网上怎么这么多复制粘贴的,千篇一概
有不足之处 但愿你们指出相互学习,
转载请注明出处 谢谢!