zoukankan      html  css  js  c++  java
  • Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略

    前言

        几乎在所有的应用程序中,缓存都是一个永恒的话题,恰当的使用缓存可以有效提高应用程序的性能;在某些业务场景下,使用缓存依赖会有很好的体验;在 Asp.Net Core 中,支持了多种缓存组件,这其中最基础也最易用的当属 IMemoryCache,该接口表示其存储依赖于托管程序服务器的内存,下面要介绍的内容就是基于 IMemoryCache 的缓存依赖。

    1. IMemoryCache 的实现

    Asp.Net Core 内部实现了一个继承自 IMemoryCache 接口的类 MemoryCache
    这几乎已成惯例,一旦某个接口被列入 SDK 中,其必然包含了一个默认实现

    1.1 使用 IMemoryCache

    在 Asp.Net Core 中要使用 IMemoryCache 非常简单,只需要在 Startup 的 ConfigureServices 方法加入一句代码 services.AddMemoryCache() 即可

    1.  
      public void ConfigureServices(IServiceCollection services)
    2.  
      {
    3.  
      services.AddMemoryCache();
    4.  
      ...
    5.  
      }

    1.2 在控制器中使用 IMemoryCache

    1.  
      [Route("api/[controller]")]
    2.  
      [ApiController]
    3.  
      public class HomeController : ControllerBase
    4.  
      {
    5.  
      private IMemoryCache cache;
    6.  
      public HomeController(IMemoryCache cache)
    7.  
      {
    8.  
      this.cache = cache;
    9.  
      }
    10.  
       
    11.  
      [HttpGet]
    12.  
      public ActionResult<IEnumerable<string>> Get()
    13.  
      {
    14.  
      cache.Set("userId", "0001");
    15.  
      return new string[] { "value1", "value2" };
    16.  
      }
    17.  
       
    18.  
      [HttpGet("{id}")]
    19.  
      public ActionResult<string> Get(int id)
    20.  
      {
    21.  
      return cache.Get<string>("userId");
    22.  
      }
    23.  
      }

    上面的代码表示在 HomeController 控制器的构造方法中使用注入的方式获得了一个 IMemoryCache 对象,在 Get() 方法中增加了一条缓存记录 "userId=0001",然后在 Get(int id) 接口中提取该缓存记录
    运行程序,分别调用 Get() 和 Get(int id) 接口,获得下面的输出信息

    • 调用 Get() 接口

    • 调用 Get(int id) 接口

    这看起来非常容易,几乎不用什么思考,你就学会了在 Asp.Net Core 中使用缓存,容易使用,这非常重要,这也是一门语言广泛推广的根本态度

    2. 应用缓存策略

    IMemoryCache 还包含了一个带参数的构造方法,让我们可以对缓存进行灵活的配置,该配置由类 MemoryCacheOptions 决定

    2.1 MemoryCacheOptions 配置,MemoryCacheOptions的配置项目不多,看下面的代码

    1.  
      public class MemoryCacheOptions : IOptions<MemoryCacheOptions>
    2.  
      {
    3.  
      public MemoryCacheOptions();
    4.  
       
    5.  
      public ISystemClock Clock { get; set; }
    6.  
       
    7.  
      [Obsolete("This is obsolete and will be removed in a future version.")]
    8.  
      public bool CompactOnMemoryPressure { get; set; }
    9.  
       
    10.  
      public TimeSpan ExpirationScanFrequency { get; set; }
    11.  
       
    12.  
      public long? SizeLimit { get; set; }
    13.  
       
    14.  
      public double CompactionPercentage { get; set; }
    15.  
      }
    • ISystemClock:系统时钟,默认值为 null,官方文档对此属性没有说明,我也不知道是干什么用的,哪位大神求告知其作用和原理
    • ExpirationScanFrequency:对过期缓存的扫描间隔时间
    • SizeLimit:缓存区可存储记录条目数量
    • CompactionPercentage:在缓存过期策略生效的时候,对缓存进行压缩的百分比

    上面的这个配置非常简单,在系统中应用类似下面的代码这样

    1.  
      public void ConfigureServices(IServiceCollection services)
    2.  
      {
    3.  
      services.AddMemoryCache(options =>
    4.  
      {
    5.  
      options.CompactionPercentage = 0.02d;
    6.  
      options.ExpirationScanFrequency = TimeSpan.FromMinutes(5);
    7.  
      options.SizeLimit = 1024;
    8.  
      });
    9.  
      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    10.  
      }

    上面的缓存策略设置为缓存压缩比为 2%,每 5 分钟进行一次过期缓存的扫描,最大缓存空间大小限制为 1024
    使用方法不变

    2.1 单个键缓存策略

    由于缓存的所有键其缓存过期优先级都是默认的 Normal,可能我们需要在某些业务场景下,让某些缓存值设置一个较高的优先级,比如设置永远都不过期,这样即使缓存达到最大限制条数以后也不会对其进行清理

    • 缓存优先级,该值为一个枚举类型,分别是 低、普通、高、永不移除,开发者可以根据不同的业务场景灵活设置
    1.  
      public enum CacheItemPriority
    2.  
      {
    3.  
      Low = 0,
    4.  
      Normal = 1,
    5.  
      High = 2,
    6.  
      NeverRemove = 3
    7.  
      }
    • 设置策略,下面就使用 MemoryCacheEntryOptions 对单个键值进行应用策略
    1.  
      [HttpGet]
    2.  
      public ActionResult<IEnumerable<string>> Get()
    3.  
      {
    4.  
      MemoryCacheEntryOptions entry = new MemoryCacheEntryOptions
    5.  
      {
    6.  
      Priority = CacheItemPriority.NeverRemove
    7.  
      };
    8.  
      cache.Set("userId", "0001", entry);
    9.  
       
    10.  
      return new string[] { "value1", "value2" };
    11.  
      }

    上面的代码表示,我们对缓存键 "userId" 应用了一个 “永不移除” 的策略,当然,还可以对单个值做非常多的策略,比如现在 "userId" 的值大小等等,有兴趣的同学可以深入了解 MemoryCacheEntryOptions 类

    3. 使用缓存依赖策略

    缓存依赖的意思是表示,一个或者多个缓存依赖于某个缓存,当某个缓存过期的时候,对其有依赖条件的其它缓存也会过期,在某些应用场景下,缓存依赖非常有用

    3.1 创建 TokenController 并登录后注册依赖、获取缓存、移除缓存接口

    以下示例使用一个模拟用户登录/登出的业务场景

    1.  
      [Route("api/[controller]")]
    2.  
      [ApiController]
    3.  
      public class TokenController : ControllerBase
    4.  
      {
    5.  
      private IMemoryCache cache;
    6.  
      public TokenController(IMemoryCache cache)
    7.  
      {
    8.  
      this.cache = cache;
    9.  
      }
    10.  
       
    11.  
      // 创建注册依赖
    12.  
      [HttpGet("login")]
    13.  
      public ActionResult<string> Login()
    14.  
      {
    15.  
      var cts = new CancellationTokenSource();
    16.  
      cache.Set(CacheKeys.DependentCTS, cts);
    17.  
      using (var entry = cache.CreateEntry(CacheKeys.UserSession))
    18.  
      {
    19.  
      entry.Value = "_x0123456789";
    20.  
      entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
    21.  
      cache.Set(CacheKeys.UserShareData, "这里是共享的数据", new CancellationChangeToken(cts.Token));
    22.  
      cache.Set(CacheKeys.UserCart, "这里是购物车", new CancellationChangeToken(cts.Token));
    23.  
      }
    24.  
      return "设置依赖完成";
    25.  
      }
    26.  
       
    27.  
      // 获取缓存
    28.  
      [HttpPost("getkeys")]
    29.  
      public IActionResult GetKeys()
    30.  
      {
    31.  
      var userInfo = new
    32.  
      {
    33.  
      UserSession = cache.Get<string>(CacheKeys.UserSession),
    34.  
      UserShareData = cache.Get<string>(CacheKeys.UserShareData),
    35.  
      UserCart = cache.Get<string>(CacheKeys.UserCart)
    36.  
      };
    37.  
       
    38.  
      return new JsonResult(userInfo);
    39.  
      }
    40.  
       
    41.  
      // 移除缓存
    42.  
      [HttpPost("logout")]
    43.  
      public ActionResult<string> LogOut()
    44.  
      {
    45.  
      cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
    46.  
       
    47.  
      var userInfo = new
    48.  
      {
    49.  
      UserSession = cache.Get<string>(CacheKeys.UserSession),
    50.  
      UserShareData = cache.Get<string>(CacheKeys.UserShareData),
    51.  
      UserCart = cache.Get<string>(CacheKeys.UserCart)
    52.  
      };
    53.  
       
    54.  
      return new JsonResult(userInfo);
    55.  
      }
    56.  
       
    57.  
      // 过期通知
    58.  
      private static void DependentEvictionCallback(object key, object value, EvictionReason reason, object state)
    59.  
      {
    60.  
      Console.ForegroundColor = ConsoleColor.Yellow;
    61.  
      Console.WriteLine("Key:{0} 已过期,依赖于该 Key 的所有缓存都将过期而处于不可用状态", key);
    62.  
      Console.ForegroundColor = ConsoleColor.Gray;
    63.  
      }
    64.  
      }

    上面的代码使用 CancellationTokenSource 用作事件通知源,当移除 CacheKeys.DependentCTS 并触发 CancellationTokenSource.Cancel() 方法后,将异步触发 DependentEvictionCallback(object key, object value, EvictionReason reason, object state)委托;此时,托管程序收到一个通知,用户已登出,已移除用户相关缓存,任何移除接口尝试再次读取 CacheKeys 项,此时,返回值为空

    3.2 运行程序,分别调用 login/getkeys/logout 接口,分别得到以下输出结果

    • login 登录后注册依赖

    • getkeys 获取缓存

    • logout 移除缓存,尝试再次读取 CacheKeys 项,此时,返回值为空

    • 控制台输出移除通知(黄色字体部分信息)

    可以看到,在用户登录登出这个业务场景下,使用缓存依赖项对其相关缓存进行管理,还是非常方便的,当用户退出登录后,即清空其所有相关缓存

    结束语

      • 本文通过实例介绍了 IMemoryCache 的简单使用方法
      • 针对单个缓存键,也可以对其进行应用策略
      • 通过使用缓存依赖策略,可以在某些业务场景中有非常好的应用体验
      • 注意:当使用全局缓存策略 SizeLimit 时,每个键都需要设置一个大小
      • IMemoryCache 依赖于托管服务器等内存,一旦重启,缓存数据将立即被释放
  • 相关阅读:
    解惑如何保证数组元素的可见性(yet)
    为什么内存锁在有事务切面的情况下会形同虚设 隔离级别与事务
    小事故合集
    第4种打整包插件,urlfactory already set
    三目运算符与字节码阅读
    servlet application/x-www-form-urlencoded 坑
    多实例重复发邮件
    当动态代理遇到ioc (五)使用cglib切面与自定义类加载器构建独有环境aop日志
    mac笔记本如何重制secureCRT的体验期|试用版本
    npm install出现的错误
  • 原文地址:https://www.cnblogs.com/bruce1992/p/14062239.html
Copyright © 2011-2022 走看看