ASP.NET Core学习之路02

本文章是我听B站杨中科的所做的笔记

杨中科B站视频链接:.NET 6教程,.Net Core 2022视频教程,杨中科主讲_哔哩哔哩_bilibili

程序员的性能优化万金油:缓存

什么是缓存

缓存(Caching)是系统优化中简单又有效的工具,投入小收效大。数据库中的索引等简单有效的优化功能本质上都是缓存

缓存的概念

1、缓存命中

2、缓存命中率

3、缓存数据不一致

多级缓存

ASP.NET Core客户端响应缓存

cache-control

1、RFC7324是HTTP协议中对缓存进行控制的规范,其中重要的是cache-control这个响应报文头。服务器如果cache-control:max-age=60,则表示服务器指示浏览器端"可以缓存这个响应内容60秒"

2、我们只要给需要进行缓存控制的控制器的操作方法添加ResponseCacheAttribute这个Attribute,ASP.NET Core会自动添加cache-control报文头

3、验证:编写一个返回当前时间的Action方法。分别加和不加ResponseCacheAttribute看区别。也F12看看Network

4、缺点:各个浏览器缓存是相互独立的,每个浏览器都得请求一遍服务器端,再进行缓存,缓存不共享

ASP.NET Core服务端响应缓存

Response Caching Middleware

1、如果ASP.NET Core中安装了“响应缓存中间件”,那么ASP.NET Core不仅会继续根据[ResponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务器端也会按照[ResponseCache]的设置来对响应进行服务器端缓存。和客户端缓存的区别?来自多个不同客户端的相同请求。

2、“响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力。

3、用法:app.MapControllers()之前加上app.UseResponseCaching()。请确保app.UseCors()写到app.UseResponseCacheing()之前

演示效果

1、大部分浏览器都是支持RFC7324规范的,所以不方便用来测试服务端响应缓存。用默认忽略RFC7324规范的PostMan测试。试一下请求服务器端

2、可以在浏览器的“开发人员工具”中禁用缓存,但是和PostMan中不一致,为什么?“cache-control:no-cache”

3、也可以让PostMan在请求报文头中加如“cache-control:no-cache”,只要在Postman的设置中开启【Send no-cache headers】

服务器端响应缓存很鸡肋

1、无法解决恶意请求给服务器带来的压力

2、服务器端响应缓存还有很多限制,包括但不限于:响应状态码为200的Get或者HEAD请求才可能被缓存;报文头中不能含有Authorization、Set-Cookie等。

Authorization为什么?:把一个浏览器响应的具体用户数据的缓存下来,给到另外一个用户浏览器不现实

3、不怪他,honor RFC7234.It's a feature,not a bug

4、怎么办呢?采用内存缓存、分布式缓存等

ASP.NET Core中的内存缓存

内存缓存

1、把缓存数据放到应用程序的内存。内存缓存中保存的是一系列的键值对,就像Dictionaty类型一样

2、内存缓存的数据保存再当前运行的网站程序的内存中,是和进程相关的。因为再Web服务器中,多个不同的网站时运行在不同的进程中的,因此不同网站的内存缓存是不会互相干扰的,而且网站重启后,内存缓存中所有数据也就都被清空了。

内存缓存的用法

1、启用:builder.Service.AddMemoryCache()

2、注入IMemoryCache接口,查看接口的方法:TryGetValue、Remove、Set、GetOrCreate、GetOrCreateAsync

3、用GetOrCreateAsync讲解

public async Task<Book[]> GetBooks()
{
    logger.LogInformation("开始执行GetBooks");
    var items = await memCache.GetOrCreateAsync("AllBooks", async (e) =>
    {
        logger.LogInformation("从数据库中读取数据");
        return await dbCtx.Books.ToArrayAsync();
    });
    logger.LogInformation("把数据返回给调用者");
    return items;
}

缓存的过期时间策略

缓存的过期时间

1、上面的例子中的缓存不会过期,除非重启服务器。

2、解决方法:在数据改变的时候调用Remove或者Set来删除或者修改缓存(优点:及时);过期时间(只要过期时间比较短,缓存数据不一致的情况也不会持续很长时间)

3、两种过期时间策略:绝对过期时间、滑动过期时间。它们分别是什么?

缓存的绝对过期时间

1、GetOrCreaeteAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置

2、AbsoluteExpirationRelativeToNow用来设定缓存项的绝对过期时间

缓存的滑动过期时间

1、ICacheEntry的SlidingExpiration属性用来设定缓存项的滑动过期时间

两种过期时间混用

使用滑动过期时间策略,如果一个缓存项一直被频繁访问,那么这个缓存项就会一直被续期而不过期。可以对一个缓存项同时设定滑动过期时间和绝对过期时间,并且把绝对过期时间设定的比滑动过期时间长,这样缓存项的内容会在绝对过期时间内随着访问被滑动续期,但是一旦超过了绝对过期时间,缓存项就会被删除

内存缓存的是与非

1、无论用哪种过期时间策略,程序中都会存在缓存数据不一致的情况。部分系统(博客等)无所谓,部分系统不能忍受(比如金融)

2、可以通过其他机制获取数据源改变的信息,再通过代码调用IMemoryCache的Set方法更新缓存

缓存穿透问题

什么是缓存穿透

string cacheKey = "Book" + id;//缓存键
Book? b = memCache.Get<Book?>(cacheKey);
if(b==null)//如果缓存中没有数据
{
    //查询数据库,然后写入缓存
    b = await dbCtx.Books.FindAsync(id);
    memCache.Set(cacheKey, b);
}

缓存穿透的解决方案

1、解决方法:把"查不到"也当成一个数据放入缓存

2、我们用GetOrCreateAsync方法即可,因为它会把null值也当成合法的缓存值

string cacheKey = "Book" + id;
var book = await memCache.GetOrCreateAsync(cacheKey, async (e) => {
    var b = await dbCtx.Books.FindAsync(id);
    logger.LogInformation("数据库查询
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值