Asp.Net Core 輕鬆學-在.Net Core 使用緩存和配置依賴策略

前言

    幾乎在全部的應用程序中,緩存都是一個永恆的話題,恰當的使用緩存能夠有效提升應用程序的性能;在某些業務場景下,使用緩存依賴會有很好的體驗;在 Asp.Net Core 中,支持了多種緩存組件,這其中最基礎也最易用的當屬 IMemoryCache,該接口表示其存儲依賴於託管程序服務器的內存,下面要介紹的內容就是基於 IMemoryCache 的緩存依賴。git

1. IMemoryCache 的實現

Asp.Net Core 內部實現了一個繼承自 IMemoryCache 接口的類 MemoryCache
這幾乎已成慣例,一旦某個接口被列入 SDK 中,其必然包含了一個默認實現github

1.1 使用 IMemoryCache

在 Asp.Net Core 中要使用 IMemoryCache 很是簡單,只須要在 Startup 的 ConfigureServices 方法加入一句代碼 services.AddMemoryCache() 便可api

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMemoryCache();
            ...
        }
1.2 在控制器中使用 IMemoryCache
[Route("api/[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        private IMemoryCache cache;
        public HomeController(IMemoryCache cache)
        {
            this.cache = cache;
        }

        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            cache.Set("userId", "0001");
            return new string[] { "value1", "value2" };
        }

        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            return cache.Get<string>("userId");
        }
    }

上面的代碼表示在 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的配置項目很少,看下面的代碼
public class MemoryCacheOptions : IOptions<MemoryCacheOptions>
    {
        public MemoryCacheOptions();

        public ISystemClock Clock { get; set; }

        [Obsolete("This is obsolete and will be removed in a future version.")]
        public bool CompactOnMemoryPressure { get; set; }

        public TimeSpan ExpirationScanFrequency { get; set; }

        public long? SizeLimit { get; set; }

        public double CompactionPercentage { get; set; }
    }
  • ISystemClock:系統時鐘,默認值爲 null,官方文檔對此屬性沒有說明,我也不知道是幹什麼用的,哪位大神求告知其做用和原理
  • ExpirationScanFrequency:對過時緩存的掃描間隔時間
  • SizeLimit:緩存區可存儲記錄條目數量
  • CompactionPercentage:在緩存過時策略生效的時候,對緩存進行壓縮的百分比

上面的這個配置很是簡單,在系統中應用相似下面的代碼這樣性能

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMemoryCache(options =>
            {
                options.CompactionPercentage = 0.02d;
                options.ExpirationScanFrequency = TimeSpan.FromMinutes(5);
                options.SizeLimit = 1024;
            });
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

上面的緩存策略設置爲緩存壓縮比爲 2%,每 5 分鐘進行一次過時緩存的掃描,最大緩存空間大小限制爲 1024
使用方法不變字體

2.1 單個鍵緩存策略

因爲緩存的全部鍵其緩存過時優先級都是默認的 Normal,可能咱們須要在某些業務場景下,讓某些緩存值設置一個較高的優先級,好比設置永遠都不過時,這樣即便緩存達到最大限制條數之後也不會對其進行清理this

  • 緩存優先級,該值爲一個枚舉類型,分別是 低、普通、高、永不移除,開發者能夠根據不一樣的業務場景靈活設置
public enum CacheItemPriority
    {
        Low = 0,
        Normal = 1,
        High = 2,
        NeverRemove = 3
    }
  • 設置策略,下面就使用 MemoryCacheEntryOptions 對單個鍵值進行應用策略
[HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            MemoryCacheEntryOptions entry = new MemoryCacheEntryOptions
            {
                Priority = CacheItemPriority.NeverRemove
            };
            cache.Set("userId", "0001", entry);

            return new string[] { "value1", "value2" };
        }

上面的代碼表示,咱們對緩存鍵 "userId" 應用了一個 「永不移除」 的策略,固然,還能夠對單個值作很是多的策略,好比如今 "userId" 的值大小等等,有興趣的同窗能夠深刻了解 MemoryCacheEntryOptions 類code

3. 使用緩存依賴策略

緩存依賴的意思是表示,一個或者多個緩存依賴於某個緩存,當某個緩存過時的時候,對其有依賴條件的其它緩存也會過時,在某些應用場景下,緩存依賴很是有用

3.1 建立 TokenController 並登陸後註冊依賴、獲取緩存、移除緩存接口

如下示例使用一個模擬用戶登陸/登出的業務場景

[Route("api/[controller]")]
    [ApiController]
    public class TokenController : ControllerBase
    {
        private IMemoryCache cache;
        public TokenController(IMemoryCache cache)
        {
            this.cache = cache;
        }

        // 建立註冊依賴
        [HttpGet("login")]
        public ActionResult<string> Login()
        {
            var cts = new CancellationTokenSource();
            cache.Set(CacheKeys.DependentCTS, cts);
            using (var entry = cache.CreateEntry(CacheKeys.UserSession))
            {
                entry.Value = "_x0123456789";
                entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
                cache.Set(CacheKeys.UserShareData, "這裏是共享的數據", new CancellationChangeToken(cts.Token));
                cache.Set(CacheKeys.UserCart, "這裏是購物車", new CancellationChangeToken(cts.Token));
            }
            return "設置依賴完成";
        }

        // 獲取緩存
        [HttpPost("getkeys")]
        public IActionResult GetKeys()
        {
            var userInfo = new
            {
                UserSession = cache.Get<string>(CacheKeys.UserSession),
                UserShareData = cache.Get<string>(CacheKeys.UserShareData),
                UserCart = cache.Get<string>(CacheKeys.UserCart)
            };

            return new JsonResult(userInfo);
        }

        // 移除緩存
        [HttpPost("logout")]
        public ActionResult<string> LogOut()
        {
            cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();

             var userInfo = new
            {
                UserSession = cache.Get<string>(CacheKeys.UserSession),
                UserShareData = cache.Get<string>(CacheKeys.UserShareData),
                UserCart = cache.Get<string>(CacheKeys.UserCart)
            };

            return new JsonResult(userInfo);
        }

        // 過時通知
        private static void DependentEvictionCallback(object key, object value, EvictionReason reason, object state)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Key:{0} 已過時,依賴於該 Key 的全部緩存都將過時而處於不可用狀態", key);
            Console.ForegroundColor = ConsoleColor.Gray;
        }
    }

上面的代碼使用 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 依賴於託管服務器等內存,一旦重啓,緩存數據將當即被釋放

示例代碼下載

https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.MemoryCacheDemo

相關文章
相關標籤/搜索