Asp.Net Core缓存管理
Posted 厦门德仔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Asp.Net Core缓存管理相关的知识,希望对你有一定的参考价值。
ASP.NET Core 客户端响应缓存
Cache-control
1.RFC7324是HTTP协议中对缓存进行控制的规范,其中重要的是cache-control这个响应头。服务器如返回cache-control:max-age=60,则表示服务器指示浏览器端"可以缓存这个响应内容60秒"
2.我们只要给需要进行缓存控制的控制器的操作方法添加ResponseCacheAttribut这个Attribute,ASP.NET Core会自动添加cache-control报文头
3.验证:编写一个返回当前的Action方法,分别加和不加ReponseCacheAttribute看区别。也可以F12看看Network
[ResponseCache(Duration =20)]
[HttpGet]
public DateTime Index()
return System.DateTime.Now;
ASP.NET Core 服务器端响应缓存(鸡肋)
- 如果ASP.NET Core中安装了“响应缓存中间件”,那么ASP.NET Core不仅会继续根据[ReponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务端也会按照[ResponseCache]的设置来对响应进行服务器端缓存。和客户端缓存的区别?来自多个不同客户端的相同请求。
- “响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力
- 用法:app.MapController()之前加上app.UseResponseCaching()。请确保app.UseCors()写到app.UseResponseCaching()之前。
演示效果
- 大部分浏览器都是支持RFC7324规范的,所以不方便用来测试服务器端响应缓存。用默认忽略RFC7324规范的PostMan测试。试一下请求服务器端。
- 可以浏览器的“开发人员工具”中禁用缓存的,但是和PostMan中不一致,为何?“cache-control:no-cache”
- 也可以让Postman在请求报文头中加入"cache-control:no-cache",只要在Postman的设置中开启【Send no-cache headers】
ASP.NET Core 内存缓存
内存缓存(In-memory cache)
- 把缓存数据放到运用程序。内存缓存中保存的是一系列的键值怼,就像
Dictionary类型一样。 - 内存缓存的数据保存在当前运行的网站程序的内存中,是和进程相关的。
因为在WEB服务器中,多个不同的网站时运行在不同的进程中,因此不同
网站的内存缓存时不会互相干老的,而且网站重启后,村村缓存中的所有数据也都被清空了。
内存缓存用法
- 启用:builder.Services.AddMemoryCache()
- 注入IMemoryCache接口,查看接口的方法:
TryGetValue,Remove,Set,GetOrCreate,GetOrCreateAsync
3. 用GetOrCreateAsync讲解
Public async Task<Book[]> GetBooks()
Looger.LogInformation("开始执行GetBooks"):
Var items=await memCache.GetOrCreateAsync("AllBooks",async€=>
Logger.LogInfromaion("从数据库读取数据");
Return await dbCtx.Books.toArrayAsync();
);
Logger.LogInfromaion("把数据返回给调用者");
Return items;
演示:
public class MyDbContext
public static Task<Book?> GetByIdAsync(long id)
var result = GetById(id);
return Task.FromResult(result);
public static Book GetById(long id)
switch (id)
case 0:
return new Book(0,"零基础趣学C语言");
case 1:
return new Book(1,"J2EE开发全程实录");
case 2:
return new Book(2, "程序员的SQL金典");
default:
return null;
break;
[ApiController]
[Route("api/[controller]/[action]")]
public class TestController : Controller
private readonly IMemoryCache memoryCache;
private readonly ILogger<TestController> logger;
public TestController(IMemoryCache memoryCache, ILogger<TestController> logger)
this.memoryCache = memoryCache;
this.logger = logger;
[HttpGet]
public async Task<ActionResult<Book?>> GetBookById(long id)
Book? result = MyDbContext.GetById(id);
//GetOrCreateAsync 二合一:1)从缓存取数据 2)从数据源取数据,并且返回给调用者及保存到缓存
logger.LogDebug($"开始执行GetBookById,id=id");
Book? b=await memoryCache.GetOrCreateAsync("Book" + id,
async (e) =>
logger.LogDebug($"缓存里没有找到,到数据库中查一查,id=id");
return await MyDbContext.GetByIdAsync(id);
);
logger.LogDebug($"GetOrCreateAsync结果b");
if (b == null)
return NotFound($"找不到id=id的书");
else
return b;
[ResponseCache(Duration =20)]
[HttpGet]
public DateTime Index()
return System.DateTime.Now;
ASP.NET Core 缓存的过期时间策略
缓存的过期时间
- 上面的例子中的缓存不会过期,除非重启服务器。
- 解决办法:在数据改变的时候调用Remove或Set来删除或者修改缓存(优点:及时)过期时间(只要过期时间比较短,缓存数据不一致的清空也不会持续很长时间。)
- 两种过期时间策略:绝对过期时间,滑动过期时间。他们分别是什么?
缓存的绝对过期时间 - GetOrCreateAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置。
- AbsoluteExpirationRelativeToNow用来设定缓存项的绝对过期时间
缓存的滑动过期时间
ICacheEntry的SlidingExpiration属性用来设定缓存项的滑动过期时间
两种过期时间混用
使用滑动过期时间策略,如果一个缓存项目一直被频繁访问,那么这个缓存项就会一直被持续而不过期。可以对一个缓存项同时设定滑动过期时间和绝对过期时间,并且把绝对过期时间设定的比滑动过期时间长,这样缓存项的内容会在绝对过期时间内随着访问被滑动续期,但是以一旦超过了绝对过期时间,缓存项目就会被删除。
内存缓存的是与非 - 无论用哪种过期时间策略,程序种都会在缓存数据不一致的情况。部分系统(博客等)无所谓,部分系统不能忍受(比如金融)
- 可以通过其他机制获取数据源改变的消息,在通过代码调用IMemoryCache的Set方法更新缓存。
ASP.NET Core 缓存穿透
什么是缓存穿透
String cacheKey-“Book”+id;//缓存键
Book? b=memCache.Get<Book?>(cachekey);
If(b==null) //如果缓存中没有数据
//查询数据库,然后写入缓存
b=awati dbCtx.Books.FindAsync(id);
memCache.Set(cacheKey,b);
缓存穿透的解决方案
- 解决方法:把“查不到”也当成一个数据放入缓存。
- 我们用GetIOrCreateAsync方法即可,因为它会把null值也当成合法的缓存值
String cacheky="Book"+id;
Var book=await memCache.GetOrCreateAsync(cachkey,async€=>)
Var b= await dbCtx.Books.FindAsync(id);
Logger.LogInformation("数据库查询:0",b==null?"为空":"不为空");
Return b;
Logger.LogInformation("DEMO5执行结束查询:0",b==null?"为空":"不为空");
[HttpGet]
public async Task<ActionResult<Book?>> GetBookById(long id)
Book? result = MyDbContext.GetById(id);
Console.WriteLine($"开始执行GetBookById,id=id");
Book? b=await memoryCache.GetOrCreateAsync("Book" + id,
async (e) =>
Console.WriteLine($"缓存里没有找到,到数据库中查一查,id=id");
//e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);//缓存有效期10秒
//e.SlidingExpiration = TimeSpan.FromSeconds(10);
Book? d= await MyDbContext.GetByIdAsync(id);
Console.WriteLine("从数据库中查询的结果是"+(d==null?"null":d));
return d;
);
Console.WriteLine($"GetOrCreateAsync结果b");
if (b == null)
return NotFound($"找不到id=id的书");
else
return b;
ASP.NETCore缓存雪崩的问题
缓存雪崩
1.缓存项集中过期引起缓存雪崩
2.解决办法:在基础过期时间之上,再加一各随机的过期时间。
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Random.Shared.Next(10,15));
//过期随机时间
分布式缓存
分布式缓存服务器
1.常用的分布式缓存服务器Redis,Memcached等
2.NET Core中提供了同意的分布式缓存服务器的操作接口IDistributedCache,用法和内存缓存类似。
3.分布式缓存和内存缓存的区别:缓存之的类型为Byte[],需要我们进行类型转换,也提供了一些按照string类型存取缓存值的扩展方法。
用什么做缓存服务器
1.用SQLServer做缓存性能并不好
2.,Memcached是缓存专用,性能非常高,但是集群,高可用等方法比较弱,而且有"缓存键的最大长度为250字节"等限制。可以按照EnyimMemcachedCore这个第三方NuGet包。
3.Redis不局限于缓存,Redis做缓存服务器比Memcached性能稍差,但Redis的高可用,集群等方便非常强大,适合在数据量大,高可用性等场合使用
以上是关于Asp.Net Core缓存管理的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core中的缓存[1]:如何在一个ASP.NET Core应用中使用缓存