首页 > 其他分享 >缓存

缓存

时间:2024-07-27 21:08:06浏览次数:8  
标签:缓存 return 过期 LogInformation 内存 logger

你是我想和全世界炫耀,又舍不得和任何人分享的人。 --zhu
缓存定义
缓存(Caching)是系统优化中简单又有效的工具,投入小收效大。数据库中的索引等简单有效的优化功能本质上都是缓存。

多级缓存
浏览器-->网关服务器-->Web服务器-->数据库服务器。

客户端响应缓存
1、RFC73224是HTTP协议中对缓存进行控制的规范,其中重要的是cache-control这个响应报文头。服务器如果返回cache-control:max-age=60,表示服务器指示浏览器端“可以缓存这个响应内容60秒”。
2、我们只要给需要进行缓存控制的控制器的操作方法添加ResponseCacheAttribute这个Attribute,ASP.NET Core会自动添加cache-control报文头。

public class TestController:ControllerBase
{
  [ResposeCache(Duration =20)]
  [HttpGet]
  public DateTime Now()
  {
    return DateTime.Now;
  }
}

服务器端响应缓存
1、如果ASP.NET Core中安装了“响应式缓存中间件”,那么AP.NET Core不仅会继续根据[ResponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务器端也会按照[ResponseCache]的设置来响应进行服务器端缓存。和客户端缓存区别:来自多个不同客户端的相同请求。
2、“响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力。
3、用法:app.MapControllers()之前加上app.UseResponseCaching()。确保app.UseCors()写到app.UserResponseCaching()之前。
4、问题:
1)无法解决恶意请求给服务器带来的压力。
2)限制较多:响应码为200的GET或者HEAD响应才可能被缓存;报文头中不能含有Authorization、Set-Cookie等。
3)建议采用内存缓存、分布式缓存。

内存缓存(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()
{
  logger.LogInformation("开始执行GetBooks");
  var items = await memCache.GetOrCreateAsync("AllBooks",async(e)=>
  {
    logger.LogInformation("无缓存数据,从数据库获取");
    return awwit dbCtx.Books.ToArrayAsync();
  });
  logger.LogInformation("把数据返回给调用者");
  return items;
}

缓存的过期时间
1、以上缓存不会过期,只能重启服务器。
2、解决方法:在数据改变的时候调用Remove或者Set来删除或者修改缓存(优点:及时);过期时间(只要过期时间比较短,缓存数据不一致的情况也不会持续很长时间)。
3、绝对过期时间、滑动过期时间。

绝对过期时间
1、GetOrCreateAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置。
2、AbsoluteExpirationRelativeToNow用来设定缓存项的绝对过期时间。

public async Task<Book[]> GetBooks()
{
  logger.LogInformation("开始执行GetBooks");
  var items = await memCache.GetOrCreateAsync("AllBooks",async(e)=>
  {
    logger.LogInformation("无缓存数据,从数据库获取");
    e.AbsoluteExpirationRelativeToNow =TimeSpan.FromSeconds(10);//缓存有效期10秒
    return awwit dbCtx.Books.ToArrayAsync();
  });
  logger.LogInformation("把数据返回给调用者");
  return items;
}

滑动过期时间
1、缓存没过期时再请求一次,缓存续命一次。
2、ICacheEnty的SlidingExpiration属性用来设定缓存项的滑动过期时间。

public async Task<Book[]> GetBooks()
{
  logger.LogInformation("开始执行GetBooks");
  var items = await memCache.GetOrCreateAsync("AllBooks",async(e)=>
  {
    logger.LogInformation("无缓存数据,从数据库获取");
    e.SlidingExpiration = TimeSpan.FromSeconds(10);//缓存有效期10秒
    return awwit dbCtx.Books.ToArrayAsync();
  });
  logger.LogInformation("把数据返回给调用者");
  return items;
}

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

public async Task<Book[]> GetBooks()
{
  logger.LogInformation("开始执行GetBooks");
  var items = await memCache.GetOrCreateAsync("AllBooks",async(e)=>
  {
    logger.LogInformation("无缓存数据,从数据库获取");
    e.SlidingExpiration = TimeSpan.FromSeconds(30);
    e.SlidingExpiration = TimeSpan.FromSeconds(10);
    return awwit dbCtx.Books.ToArrayAsync();
  });
  logger.LogInformation("把数据返回给调用者");
  return items;
}

内存缓存总结
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);
}

上述代码,遇到不存在缓存键值时,会查询数据库,如果有人恶意频繁传入不存在的Id,每次都要查数据库,给数据库造成压力。

缓存穿透解决方法
1、把数据库查不到的当成一个指定数据放入缓存。
2、我们用GetOrCreateAsync方法即可,因为它会把null值当成合法的缓存值。

string cacheKey = "Book"  + id;
var book =await memoCache.GetOrCreateAsync(cacheKey,async(e) =>{
  var b=await dbAtx.Books.FindAsync(id);
  logger.LogInformation("数据库查询:{0}",b==null?"为空":"不为空");
  return b;
 });
logger.LogInformation("Demo5执行结束:{0}",b==null?"为空":"不为空");

缓存雪崩
1、缓存项集中过期引起缓存雪崩。(例如所有都堆30秒后过期)
2、解决方法:在基础过期时间上,再加一个随机过期时间。

e.AbsoluteExpirationRelativeToNow =TimeSpan.FromSeconds(Random.Shared.Next(10,19));//过期时间随机,(Random.Shared全局随机数)

缓存数据混乱

public User GetUserInfo()
{
  Guid userId=...;
  return memCache.GetOrCreate("UserInfo",(e)=>
  {
    return ctx.User.Find()userId;//要不重复的键,UserInfo改成UserInfo+Id
  })
}

分布式缓存
内存缓存效率高,但是如果集群节点数量非常多的话,重复查询时还是会把数据库整垮。
1、常用的分布式缓存服务器有Redis、Memcached等。
2、.NET Core中提供了统一的分布式缓存服务器操作接口IDistributedCache,用法和内存缓存类似。
3、分布式缓存和内存缓存的区别:缓存值的类型为byte[],需要我们进行类型转换,也提供了按照string类型存取缓存值的扩展方法。

缓存服务器选择
1、SQLServer做缓存性能不好。
2、Memcached是缓存专用,性能非常高,但是集群、高可用等方面比较弱,而且“缓存键的最大长度为250字节”限制。安装EnyimMemcachedCore包。
3、Redis不局限于缓存,Redis做缓存服务器比Memcached性能稍差,但是Redis的高可用、集群等方面强大,适合数据量大、高可用性等场景。

使用
1、NuGet安装Mircrosoft.Extensions.Caching.StackExchangeRedis
2、

builder.Services.AddStackExchangeRedisCache(options=>
{
    options.Configuration="localhost";
    options.InstanceName="yzk_";//避免混乱
});
public async Task<Book[]> GetBooks(long id)
{
  string? s = await distCache.GetStringAsync("Book"+id);
  if(s==null)
  {
    var book=await MyDbContext.GetByIdAsync(id);
    await distCache.SetStringAsync("Book"+id,JsonSerializer.Serialize(book));
  }
  else
  {
    book = JsonSerializer.Deserialize<Book?>(s);
  }
  if(book==null)
  {
    return NotFound("不存在");
  }
  else
  {
    return book;
  }
}

标签:缓存,return,过期,LogInformation,内存,logger
From: https://www.cnblogs.com/zhusichen/p/18325143

相关文章

  • 苹果电脑怎么清理缓存和垃圾 mac如何关闭正在运行的程序 苹果电脑怎么清理后台
    苹果电脑以其出色的性能和用户友好的界面而广受好评,但在使用过程中,后台程序的堆积可能会影响到系统的运行效率。太多应用和进程在后台默默运行,就像是无形的背包,让你的Mac背负了太多不必要的重量。不过,别担心,苹果电脑怎么清理后台其实并不复杂,下面这些轻松的步骤将帮助你给你的M......
  • redis的使用场景-热点数据缓存
    1.什么是缓存?把一些经常访问的数据放入缓存中,减少访问数据库的频率,减少数据库的压力,从而提高程序的性能。【内存中存储】2.缓存的原理通过上图可以看出程序首先访问缓存,如果缓存中有访问的数据会直接方会给客户端,不需要访问数据库,如果缓存中没有需要的数据则访问数据库,命中......
  • 缓存的简介以及Mybatis缓存中一级缓存和二级缓存
    简介我们所有的查询都需要连接数据库,连接数据库比较耗资源,那么如何解决耗资源的问题呢?    我们可以把一次查询的结果暂存在一个可以直接取到的地方——>内存    放在内存里的这一些查询的数据就叫缓存,这是什么意思呢,我们再次查询相同数据的时     ......
  • redis的使用场景-热点数据缓存(把经常访问的数据放入缓存减少数据库压力)
    一、使用redis实现(不推荐,会增加业务代码维护)@ServicepublicclassClazzServiceImplimplementsClazzService{@AutowiredprivateClazzDaoclazzDao; //注入mapper@AutowiredprivateRedisTemplate<String,Object>redisTemplate; //调用redis使用@Overridep......
  • 易优CMS模板标签SQL数据查询查询数据表ey_arctype,指定栏目ID的基本信息,不使用数据缓存
    【基础用法】标签:sql描述:用于获取MySQL数据库内容的标签。用法:{eyou:sqlsql=''cachetime='3600'empty='没有数据'}{$field.数据表相应的字段名称}{/eyou:sql}属性:sql=''需要查询的SQL语句cachetime='3600'数据缓存时间,默认缓存25小时,即86400秒empty=''没有数据时显示......
  • 缓存框架 Caffeine 的可视化探索与实践
    作者:vivo互联网服务器团队- WangZhiCaffeine作为一个高性能的缓存框架而被大量使用。本文基于Caffeine已有的基础进行定制化开发实现可视化功能。一、背景Caffeine缓存是一个高性能、可扩展、内存优化的Java缓存库,基于Google的GuavaCache演进而来并提供了接近最佳......
  • 一文详解 JuiceFS 读性能:预读、预取、缓存、FUSE 和对象存储
    在高性能计算场景中,往往采用全闪存架构和内核态并行文件系统,以满足性能要求。随着数据规模的增加和分布式系统集群规模的增加,全闪存的高成本和内核客户端的运维复杂性成为主要挑战。JuiceFS,是一款全用户态的云原生分布式文件系统,通过分布式缓存大幅提升I/O吞吐量,并使用成本较......
  • mybatis的二级缓存详解
    MyBatis的二级缓存是一种强大的查询缓存机制,它在默认情况下是关闭的。要启用二级缓存,需要在SQL映射文件中添加 <cache/> 标签。以下是对MyBatis二级缓存的详细解释:1.基本概念一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session。当Session冲......
  • Redis缓存面试问题解析:如何有效管理缓存失效策略?
    在技术面试中,Redis缓存是一个常见的话题。面试官往往会考察候选人对缓存机制的理解以及在实际场景中的应用能力。本文将探讨一个在Redis缓存面试中经常被问到的问题,并深入解析其背后的概念和解决方案。面试问题:如何管理Redis缓存的失效策略?问题描述:在高并发的web应用中,缓存是提......
  • 项目一缓存商品
    文章目录概要整体架构流程技术细节小结概要因为商品是经常被浏览的,所以数据库的访问量就问大大增加,造成负载过大影响性能,所以我们需要把商品缓存到redis当中,因为redis是存在内存中的,所以效率会比MySQL的快.整体架构流程 技术细节我们在缓存时需要保持数据......