Visual
一句话的事儿
缓存的优点:
- 提高网站的访问速度
- 适用于不易改变的数据
缓存的缺点:
- 仔细规划
- 奇怪的副作用
缓存的地点:
- 服务器(单服务器)
- 缓存服务器(多服务器)
- 客户端
01.In-Memory 缓存
- 最简单的
- IMemoryCache
- 适用于 Sticky Session(粘滞的会话)
- 适用于任何类型的对象
Sticky Session:In-Memory 缓存存储在 Web 服务器的内存中,只有本服务器能访问到。当 Web 应用部署在多服务器时,需保证用户访问的服务器就是之前进行缓存的服务器。
通过 services.AddMemoryCache();
在 Startup ConfigureServices 中启用内存缓存。
MemoryCacheEntryOptions:
- Absolute expiration time 绝对过期时间
- Sliding expiration time:每次请求访问缓存后,都会重置缓存的过期时间 —>滑动过期时间
- 缓存优先级
- PostEvictionDelegate:缓存数据被清除时调用该委托
在 AlbumController 中使用 In-Memory Cache:
// GET: Album
public async Task<ActionResult> Index()
{
//判断缓存中有没有自己想要的数据
if (!_memoryCache.TryGetValue(
CacheEntryConstants.AlbumsOfToday,
out List<Album> cachedAlbums))
{
//读取数据库数据
cachedAlbums = await _albumService.GetAllAsync();
//设置缓存时间
var cacheEntryOptions = new MemoryCacheEntryOptions()
//.SetAbsoluteExpiration(TimeSpan.FromSeconds(600));
.SetSlidingExpiration(TimeSpan.FromSeconds(30));
//回调,吧缓存的数据再回调回去
cacheEntryOptions.RegisterPostEvictionCallback(FillCache, this);
//设置缓存值
_memoryCache.Set(CacheEntryConstants.AlbumsOfToday, cachedAlbums, cacheEntryOptions);
}
return View(cachedAlbums);
}
private void FillCache(object key, object value, EvictionReason reason, object state)
{
// 不具体实现
Console.WriteLine("Cache entry is evicted!");
}
02.Cache Tag Helper
格式:<cache>@await Component.InvokeAsync("xxx")</cache>
- 服务器端
- 实际使用 IMemoryCache,也要求 Sticky Session
属性:
- enabled —>是否启用
- expires-on: —>绝对过期时间
- expires-after —>多久后过期
- expires-sliding —>滑动过期
- vary-by-header: —>如果请求的 header 变了,缓存就需要刷新
- vary-by-query
- vary-by-route
- vary-by-cookie
- vary-by-user
- vary-by
- priority —优先级设定
示例:
//30秒后过期
<cache expires-after="@TimeSpan.FromSeconds(30)">
@await Component.InvokeAsync("InternetStatus")
</cache>
如何测试:
- 当前这个网络连接状态,首次是读取数据库,走的是mini MVC’
- 断开网络,在30秒前,走的是缓存,所以这个时候这个viewCompoent是有用的
- 断开网络30秒后,到了过期时间,所以这一次不再读取缓存而是读取数据库,那么此时网络是断开的,所以这个viewCompoent是不起作用的。
03.分布式缓存
特点:
- 无需 Sticky Session
- 可扩展
- Web 服务器重启不会影响缓存
- 性能更好
接口与常用方法:
- IDistributedCache
- Get, GetAsync
- Set, SetAsync
- Refresh, RefreshAsync
- Remove, RemoveAsync
类型:
- 分布式 Memory Cache(仅适合开发时使用)
- 分布式 Sql Server Cache
- 分布式 Redis Cache(推荐)
Redis Cache
通过 Docker 安装 Redis:docker pull redis
如果拉取速度很慢,推荐使用阿里云的镜像加速器(简单教程)。
运行容器:docker run --name my-redis -d -p 6379:6379 redis
命名 暴露端口 6379 镜像名
docker ps
查看运行状态:
docker run -it --link my-redis:my-redis --rm redis redis-cli -h my-redis -p 6379
- -it:interactive
- —link my-redis:链接到 my-redis
- :my-redis:在里面的名也叫 my-redis
- —rm:容器停止后就删除容器
- redis:镜像是 redis
- redis-cli:运行里面的 redis-cli 程序
- -h my-redis:hostname 叫 my-redis
- -p 6379:端口 6379
测试 redis:
打开 NuGet 安装 Redis:
在 Startup 中配置 Redis:
services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "redis-for-albums";
});
在 AlbumController 中使用 Redis:
private readonly ILogger<AlbumController> _logger;
private readonly IDistributedCache _distributedCache;
private readonly IAlbumService _albumService;
private readonly HtmlEncoder _htmlEncoder;
public AlbumController(
IAlbumService albumService,
HtmlEncoder htmlEncoder,
ILogger<AlbumController> logger,
IDistributedCache distributedCache) //使用Redis缓存
{
_albumService = albumService;
_htmlEncoder = htmlEncoder;
_logger = logger;
_distributedCache = distributedCache;
}
// GET: Album
public async Task<ActionResult> Index()
{
List<Album> cachedAlbums; //缓存值
//给缓存增加Key值
var cachedAlbumsString = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
if (cachedAlbumsString == null)
{
//读取数据库中的值
cachedAlbums = await _albumService.GetAllAsync();
//将读取后的数据序列化
var serializedString = JsonConvert.SerializeObject(cachedAlbums);
//序列化后进行转换
byte[] encodedAlbums = Encoding.UTF8.GetBytes(serializedString);
//设置缓存时间
var cacheEntryOptions = new DistributedCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(30));
//放到缓存中
_distributedCache.Set(CacheEntryConstants.AlbumsOfToday, encodedAlbums, cacheEntryOptions);
}
else
{
//已经在缓存中了
//解码
byte[] encodedAlbums = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
//转换成想要的数据格式
var serializedString = Encoding.UTF8.GetString(encodedAlbums);
//转换成集合,方便读取
cachedAlbums = JsonConvert.DeserializeObject<List<Album>>(serializedString);
}
return View(cachedAlbums);
}
04.Response 响应缓存
- 基于 Header
- 客户端缓存
- 使用 ResponseCache 这个 Attribute
参数:
- Location —缓存在哪(any,null,客户端—Location = ResponseCacheLocation.Client))
- Duration —缓存时间
- NoStore —不需要缓存
- VaryByHeader —检查哪个Header决定是否缓存
01.在配置 MVC 中间件时配置 Response 缓存:
services.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
options.Filters.Add<LogResourceFilter>();
options.CacheProfiles.Add("Default",new CacheProfile
{
Duration = 60
});
options.CacheProfiles.Add("Never", new CacheProfile
{
Location = ResponseCacheLocation.None,
NoStore = true
});
});
02.Response 缓存的使用: ```csharp // 手动配置 [ResponseCache(Duration = 30, Location = ResponseCacheLocation.Client)] public IActionResult Index() { _logger.LogInformation(MyLogEventIds.HomePage, “Visiting Home Index …”); return View(); }
// 通过指定 CacheProfile 进行配置 [ResponseCache(CacheProfileName = “Default”)] public IActionResult Privacy() { return View(); }
注:
1. 必须使用非 VS 调试启动的浏览器打开页面才能测试 Response 缓存效果
1. 刷新页面时 Response 缓存不会起效
1. Response 缓存中间件的相关内容请参考[官方文档](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-2.2)
<a name="pbMx6"></a>
# 压缩
压缩传输的数据。通常针对 1K 以上的数据。
```csharp
app.UseReponseCompression();
缓存中间件
详细内容参考官方文档:Response compression in ASP.NET Core。