c#解决内存缓存的缓存雪崩和缓存穿透问题
如何搭建内存缓存这里就不多说了,不会的可以看我上一篇文章
https://blog.csdn.net/Smooth_Sailing_/article/details/130563683
什么是缓存穿透
缓存穿透就是比如如下代码
string cachekey = "book" + id;//定义id
book? b = MemoryCache.Get<book?>(cachekey); //去缓存里面查找等于id的数据
if (b == null)
{
//如果没有查到就把数据添加到缓存里面
b = await Dbcontext.eee(id);
MemoryCache.Set(cachekey, b);
}
该代码的作用是通过id去缓存里面找数据,如果等于空就去数据库里面查数据,然后添加到缓存
如果我们传入的是一个数据库里面不存在的id呢,这样会导致循环找不到,数据库里面找不到缓存里面也找不到,如果你的查询是个很消耗数据库性能的查询,那么在有人恶意传不存在的id去循环调用你这个接口,就会造成数据库的性能问题,这就是缓存穿透
解决
book? b= await MemoryCache.GetOrCreateAsync("book"+id, async (e) => {
return await Dbcontext.eee(id);
});
该代码的作用是通过id去缓存里面找数据,如果没有找到就去数据库里面查数据,然后添加到缓存
用GetOrCreateAsync方法执行,GetOrCreateAsync会把null也当成一个值存到缓存里面
什么是缓存雪崩
缓存雪崩就是比如双十一搞活动,设置0点开始抢,我们需要优化数据库性能就会把商品都添加到缓存里面,所以需要设置一个缓存过期时间,比如是5秒的过期时间,我们每隔五秒就会去数据执行一次操作拿到数据,这样就会造成数据的压力很小,一会压力突然达到顶峰然后又降下去,然后又5秒到达顶峰
这就是缓存雪崩
如何解决 那就让这个过期时间设置为一个范围内的随机时间
book? b= await MemoryCache.GetOrCreateAsync("book"+id, async (e) => {
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
//设置缓存数据绝对过期时间10秒过期
});
上面代码是设置成了固定过期时间为10秒 我们把它设置为范围内的随机时间
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
namespace 内存缓存.Controllers
{
[Route("[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IMemoryCache MemoryCache;
public ValuesController(IMemoryCache MemoryCache)
{
this.MemoryCache = MemoryCache;
}
[HttpGet]
public object q123qq(int id)
{
book? result = Dbcontext.qq(id);
if (result == null)
{
return NotFound();
}
else
{
return result;
}
}
[HttpGet]
public async Task<ActionResult<book?>> qqq(int id)
{
//string cachekey = "book" + id;
//book? b = MemoryCache.Get<book?>(cachekey);
//if (b == null)
//{
// b = await Dbcontext.eee(id);
// MemoryCache.Set(cachekey, b);
//}
//book? result = Dbcontext.qq(id);
//if (result == null)
//{
// return NotFound();
//}
//else {
// return result;
//}
//GetOrCreateAsync 是异步调用 先到缓存中查询如果没有查询到就执行方法把数据添加到缓存
Console.WriteLine($"开始执行GetOrCreateAsync查找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);//设置缓存数据滑动过期时间10秒过期
//e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Random.Shared.Next(10,15));//设值绝对过期时间为10秒到15秒的随机时间
//滑动过期时间的意思是每访问一次就续命一次,如果在规定的时间内没有访问就过期
book? q= await Dbcontext.eee(id);
if (q==null) { Console.WriteLine("没有找到数据"); }
return q;
});
Console.WriteLine($"结果是{b}");
if (b == null)
{
return NotFound("找不到数据");
}
else
{
return b;
}
}
}
public class Dbcontext
{
public static Task<book?> eee(int id)
{
var q = qq(id);
return Task.FromResult(q);
}
public static book? qq(int id)
{
switch (id)
{
case 1:
return new book(1,"1");
case 2:
return new book(2, "2");
case 3:
return new book(3, "3");
default: return null;
}
}
}
public record book(int id,string result);
}