Visual

一句话的事儿

  • 将访问的数据存储起来,从而降低对数据库的访问
  • 存储方式可以是服务器端或者是客户端
  • 常见的缓存库有:InMemoryChche,Redis,Reponse,Zip以及分布式缓存

    缓存简介

缓存的优点:

  • 提高网站的访问速度
  • 适用于不易改变的数据

缓存的缺点:

  • 仔细规划
  • 奇怪的副作用

缓存的地点:

  • 服务器(单服务器)
  • 缓存服务器(多服务器)
  • 客户端

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:

  1. // GET: Album
  2. public async Task<ActionResult> Index()
  3. {
  4. //判断缓存中有没有自己想要的数据
  5. if (!_memoryCache.TryGetValue(
  6. CacheEntryConstants.AlbumsOfToday,
  7. out List<Album> cachedAlbums))
  8. {
  9. //读取数据库数据
  10. cachedAlbums = await _albumService.GetAllAsync();
  11. //设置缓存时间
  12. var cacheEntryOptions = new MemoryCacheEntryOptions()
  13. //.SetAbsoluteExpiration(TimeSpan.FromSeconds(600));
  14. .SetSlidingExpiration(TimeSpan.FromSeconds(30));
  15. //回调,吧缓存的数据再回调回去
  16. cacheEntryOptions.RegisterPostEvictionCallback(FillCache, this);
  17. //设置缓存值
  18. _memoryCache.Set(CacheEntryConstants.AlbumsOfToday, cachedAlbums, cacheEntryOptions);
  19. }
  20. return View(cachedAlbums);
  21. }
  22. private void FillCache(object key, object value, EvictionReason reason, object state)
  23. {
  24. // 不具体实现
  25. Console.WriteLine("Cache entry is evicted!");
  26. }

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 —优先级设定

示例:

  1. //30秒后过期
  2. <cache expires-after="@TimeSpan.FromSeconds(30)">
  3. @await Component.InvokeAsync("InternetStatus")
  4. </cache>

如何测试:

  • 当前这个网络连接状态,首次是读取数据库,走的是mini MVC’
  • 断开网络,在30秒前,走的是缓存,所以这个时候这个viewCompoent是有用的
  • 断开网络30秒后,到了过期时间,所以这一次不再读取缓存而是读取数据库,那么此时网络是断开的,所以这个viewCompoent是不起作用的。

03.分布式缓存

image.png

特点:

  • 无需 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 镜像名
image.png

docker ps 查看运行状态:
image.png

docker run -it --link my-redis:my-redis --rm redis redis-cli -h my-redis -p 6379
image.png

  • -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:
image.png

打开 NuGet 安装 Redis:
image.png

在 Startup 中配置 Redis:

  1. services.AddDistributedRedisCache(options =>
  2. {
  3. options.Configuration = "localhost";
  4. options.InstanceName = "redis-for-albums";
  5. });

在 AlbumController 中使用 Redis:

  1. private readonly ILogger<AlbumController> _logger;
  2. private readonly IDistributedCache _distributedCache;
  3. private readonly IAlbumService _albumService;
  4. private readonly HtmlEncoder _htmlEncoder;
  5. public AlbumController(
  6. IAlbumService albumService,
  7. HtmlEncoder htmlEncoder,
  8. ILogger<AlbumController> logger,
  9. IDistributedCache distributedCache) //使用Redis缓存
  10. {
  11. _albumService = albumService;
  12. _htmlEncoder = htmlEncoder;
  13. _logger = logger;
  14. _distributedCache = distributedCache;
  15. }
  16. // GET: Album
  17. public async Task<ActionResult> Index()
  18. {
  19. List<Album> cachedAlbums; //缓存值
  20. //给缓存增加Key值
  21. var cachedAlbumsString = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
  22. if (cachedAlbumsString == null)
  23. {
  24. //读取数据库中的值
  25. cachedAlbums = await _albumService.GetAllAsync();
  26. //将读取后的数据序列化
  27. var serializedString = JsonConvert.SerializeObject(cachedAlbums);
  28. //序列化后进行转换
  29. byte[] encodedAlbums = Encoding.UTF8.GetBytes(serializedString);
  30. //设置缓存时间
  31. var cacheEntryOptions = new DistributedCacheEntryOptions()
  32. .SetSlidingExpiration(TimeSpan.FromSeconds(30));
  33. //放到缓存中
  34. _distributedCache.Set(CacheEntryConstants.AlbumsOfToday, encodedAlbums, cacheEntryOptions);
  35. }
  36. else
  37. {
  38. //已经在缓存中了
  39. //解码
  40. byte[] encodedAlbums = _distributedCache.Get(CacheEntryConstants.AlbumsOfToday);
  41. //转换成想要的数据格式
  42. var serializedString = Encoding.UTF8.GetString(encodedAlbums);
  43. //转换成集合,方便读取
  44. cachedAlbums = JsonConvert.DeserializeObject<List<Album>>(serializedString);
  45. }
  46. return View(cachedAlbums);
  47. }

04.Response 响应缓存

  • 基于 Header
  • 客户端缓存
  • 使用 ResponseCache 这个 Attribute

参数:

  • Location —缓存在哪(any,null,客户端—Location = ResponseCacheLocation.Client))
  • Duration —缓存时间
  • NoStore —不需要缓存
  • VaryByHeader —检查哪个Header决定是否缓存
  • 01.在配置 MVC 中间件时配置 Response 缓存:

    1. services.AddMvc(options =>
    2. {
    3. options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
    4. options.Filters.Add<LogResourceFilter>();
    5. options.CacheProfiles.Add("Default",new CacheProfile
    6. {
    7. Duration = 60
    8. });
    9. options.CacheProfiles.Add("Never", new CacheProfile
    10. {
    11. Location = ResponseCacheLocation.None,
    12. NoStore = true
    13. });
    14. });
  • 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. 注:
  2. 1. 必须使用非 VS 调试启动的浏览器打开页面才能测试 Response 缓存效果
  3. 1. 刷新页面时 Response 缓存不会起效
  4. 1. Response 缓存中间件的相关内容请参考[官方文档](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/middleware?view=aspnetcore-2.2)
  5. <a name="pbMx6"></a>
  6. # 压缩
  7. 压缩传输的数据。通常针对 1K 以上的数据。
  8. ```csharp
  9. app.UseReponseCompression();

缓存中间件

详细内容参考官方文档:Response compression in ASP.NET Core