一、概念
缓存可以通过减少生成内容所需的工作,显著提高应用的性能和可伸缩性。 缓存最适用于不常更改且生成成本很高的数据。 缓存生成的数据副本可以比从源中更快地返回。 应该以从不依赖于缓存数据的方式编写和测试应用。
内存缓存是指使用服务器内存来存储缓存的数据。 内存缓存是最简单的缓存,其基于 IMemoryCache,
IMemoryCache表示存储在 Web 服务器内存中的缓存。这种类型的缓存适用于使用会话亲和性的单个服务器或多个服务器。 会话亲和性也称为“粘滞会话”。 会话亲和性是指来自客户端的请求总是路由到同一个服务器进行处理。
二、实操演示理解内存缓存
1、新建WEB API项目:
2、修改Program.cs文件,新增注册内存缓存服务
// Add services to the container.
builder.Services.AddMemoryCache();//注册内存缓存服务
3、Controller目录下新建MemoryCacheController.cs文件
编辑以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace MemoryCacheSample.Controllers
{
[ApiController]
public class MemonryCacheController : ControllerBase
{
private readonly IMemoryCache _cache;
//构造函数注入内存缓存接口
public MemonryCacheController(IMemoryCache memory)
{
_cache = memory;
}
[Route("api/getcache/getmemorycache")]
[HttpGet]
public IActionResult get()
{
if(!_cache.TryGetValue<string>("cachetime",out var cachetime))
{
_cache.Set("cachetime", cachetime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
}
return Ok(
new
{
cachetime,
currtime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
});
}
}
}
以上代码通过使用依赖关系注入从应用引用的服务,在构造函数中请求获取IMemoryCache
实例,实现请求时使用 TryGetValue 检查是否存在key值为cachetime的缓存数据,不存在则将当前时间使用 Set 缓存到内存中,存在则返回缓存的数据
4、调试启动API项目,并请求相应的API接口
可以看到第一次请求的cachetime与currtime的值一致
当第二、第三次请求时,cachetime的值和currtime的不一致,cachetime跟上面第一次请求的值一样,说明cachetime已经存在于内存缓存之中
4、内存缓存的滑动过期时间和绝对过期时间
如果只是不断的将想要缓存的数据存入内存之中,就会存在内存泄漏、占用内存和缓存项集永不过期的风险。
1)滑动到期时间:缓存的过期时间,在规定的过期时间内每一次的访问都会重置滑动过期时间,当超过过期时间内没有请求访问,此时缓存才真正过期失效。
MemoryCacheController.cs修改添加以下代码为缓存设置滑动过期时间:
.SetSlidingExpiration(TimeSpan.FromSeconds(3)):设置滑动到期时间为3秒,3秒内的不断的请求,缓存cachetime一直不变,会不断的刷新滑动过期时间,超过3秒不请求cachetime才真正过期失效。
[Route("api/getcache/getmemorycache")]
[HttpGet]
public IActionResult get()
{
if(!_cache.TryGetValue<string>("cachetime",out var cachetime))
{
//设置缓存滑动到期时间
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
_cache.Set("cachetime", cachetime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),cacheEntryOptions);
}
return Ok(
new
{
cachetime,
currtime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
});
}
2)绝对过期时间:设置的固定缓存过期时间,当缓存进内存开始到固定时间内,缓存数据都是有效,当超过固定的过期时间,缓存就失效,不管期间是否有请求访问进入。
修改添加以下代码为缓存设置绝对过期时间:
.SetAbsoluteExpiration(TimeSpan.FromSeconds(5)):设置绝对到期时间为5秒。
if(!_cache.TryGetValue<string>("cachetime",out var cachetime))
{
//设置缓存滑动到期时间
//var cacheEntryOptions = new MemoryCacheEntryOptions()
// .SetSlidingExpiration(TimeSpan.FromSeconds(3));
//设置缓存绝对过期时间
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromSeconds(5));
_cache.Set("cachetime", cachetime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),cacheEntryOptions);
}
如果在滑动过期时间间隔内重复访问缓存的项,则该项永远不会过期,将滑动到期时间与绝对到期时间结合以确保该项过期,这才是最佳理想状态,符合实际应用场景。 绝对到期时间将上线设置为项的可缓存时间,同时如果在可调到期时间内未请求项目,仍允许项提前到期。 如果经过了可调到期间隔或绝对到期时间,则会从缓存中逐出项。
if(!_cache.TryGetValue<string>("cachetime",out var cachetime))
{
//设置缓存滑动到期时间
//var cacheEntryOptions = new MemoryCacheEntryOptions()
// .SetSlidingExpiration(TimeSpan.FromSeconds(3));
//设置缓存绝对过期时间
//var cacheEntryOptions = new MemoryCacheEntryOptions()
// .SetAbsoluteExpiration(TimeSpan.FromSeconds(5));
//设置滑动到期时间与绝对到期时间结合
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(3)).
SetAbsoluteExpiration(TimeSpan.FromSeconds(5));
_cache.Set("cachetime", cachetime = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),cacheEntryOptions);
}