【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的高可用,集群等方便非常强大,适合在数据量大,高可用性等场合使用

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...