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 服务器端响应缓存(鸡肋)

  1. 如果ASP.NET Core中安装了“响应缓存中间件”,那么ASP.NET Core不仅会继续根据[ReponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务端也会按照[ResponseCache]的设置来对响应进行服务器端缓存。和客户端缓存的区别?来自多个不同客户端的相同请求。
  2. “响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力
  3. 用法:app.MapController()之前加上app.UseResponseCaching()。请确保app.UseCors()写到app.UseResponseCaching()之前。

演示效果

  1. 大部分浏览器都是支持RFC7324规范的,所以不方便用来测试服务器端响应缓存。用默认忽略RFC7324规范的PostMan测试。试一下请求服务器端。
  2. 可以浏览器的“开发人员工具”中禁用缓存的,但是和PostMan中不一致,为何?“cache-control:no-cache”
  3. 也可以让Postman在请求报文头中加入"cache-control:no-cache",只要在Postman的设置中开启【Send no-cache headers】

ASP.NET Core 内存缓存

内存缓存(In-memory cache)

  1. 把缓存数据放到运用程序。内存缓存中保存的是一系列的键值怼,就像
    Dictionary类型一样。
  2. 内存缓存的数据保存在当前运行的网站程序的内存中,是和进程相关的。
    因为在WEB服务器中,多个不同的网站时运行在不同的进程中,因此不同
    网站的内存缓存时不会互相干老的,而且网站重启后,村村缓存中的所有数据也都被清空了。

内存缓存用法

  1. 启用:builder.Services.AddMemoryCache()
  2. 注入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 缓存的过期时间策略

缓存的过期时间

  1. 上面的例子中的缓存不会过期,除非重启服务器。
  2. 解决办法:在数据改变的时候调用Remove或Set来删除或者修改缓存(优点:及时)过期时间(只要过期时间比较短,缓存数据不一致的清空也不会持续很长时间。)
  3. 两种过期时间策略:绝对过期时间,滑动过期时间。他们分别是什么?
    缓存的绝对过期时间
  4. GetOrCreateAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置。
  5. AbsoluteExpirationRelativeToNow用来设定缓存项的绝对过期时间
    缓存的滑动过期时间
    ICacheEntry的SlidingExpiration属性用来设定缓存项的滑动过期时间
    两种过期时间混用
    使用滑动过期时间策略,如果一个缓存项目一直被频繁访问,那么这个缓存项就会一直被持续而不过期。可以对一个缓存项同时设定滑动过期时间和绝对过期时间,并且把绝对过期时间设定的比滑动过期时间长,这样缓存项的内容会在绝对过期时间内随着访问被滑动续期,但是以一旦超过了绝对过期时间,缓存项目就会被删除。
    内存缓存的是与非
  6. 无论用哪种过期时间策略,程序种都会在缓存数据不一致的情况。部分系统(博客等)无所谓,部分系统不能忍受(比如金融)
  7. 可以通过其他机制获取数据源改变的消息,在通过代码调用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);
 

缓存穿透的解决方案

  1. 解决方法:把“查不到”也当成一个数据放入缓存。
  2. 我们用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缓存管理

ASP.NET Core中的缓存[1]:如何在一个ASP.NET Core应用中使用缓存

详解Asp.Net Core 2.1+的视图缓存(响应缓存)

ASP .NET Core MemoryCache缓存

如何在 ASP.Net Core 使用 分布式缓存

如何在 ASP.Net Core 使用 内存缓存