幾乎在所有的應用程式中,緩存都是一個永恆的話題,恰當的使用緩存可以有效提高應用程式的性能;在某些業務場景下,使用緩存依賴會有很好的體驗;在 Asp.Net Core 中,支持了多種緩存組件,下麵要介紹的內容就是基於 IMemoryCache 的緩存依賴。 ...
前言
幾乎在所有的應用程式中,緩存都是一個永恆的話題,恰當的使用緩存可以有效提高應用程式的性能;在某些業務場景下,使用緩存依賴會有很好的體驗;在 Asp.Net Core 中,支持了多種緩存組件,這其中最基礎也最易用的當屬 IMemoryCache,該介面表示其存儲依賴於托管程式伺服器的記憶體,下麵要介紹的內容就是基於 IMemoryCache 的緩存依賴。
1. IMemoryCache 的實現
Asp.Net Core 內部實現了一個繼承自 IMemoryCache 介面的類 MemoryCache
這幾乎已成慣例,一旦某個介面被列入 SDK 中,其必然包含了一個預設實現
1.1 使用 IMemoryCache
在 Asp.Net Core 中要使用 IMemoryCache 非常簡單,只需要在 Startup 的 ConfigureServices 方法加入一句代碼 services.AddMemoryCache() 即可
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,可能我們需要在某些業務場景下,讓某些緩存值設置一個較高的優先順序,比如設置永遠都不過期,這樣即使緩存達到最大限制條數以後也不會對其進行清理
- 緩存優先順序,該值為一個枚舉類型,分別是 低、普通、高、永不移除,開發者可以根據不同的業務場景靈活設置
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 類
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://files.cnblogs.com/files/viter/Ron.MemoryCacheDemo.zip