一. 整體說明
1. 說明
分布式緩存通常是指在多個應用程序服務器的架構下,作為他們共享的外部服務共享緩存,常用的有SQLServer、Redis、NCache。
特別說明一下:這里的分布式是指多個應用程序服務器,而不是指將Redis或SQLServer部署成分布式集群。
2. 分布式緩存數據有以下幾個特點
A. 跨多個服務器請求
B. 服務器重新啟動和應用部署緩存仍然有效
C. 不使用本地緩存
本節主要介紹基於SQLServer和Redis的分布式緩存服務,在Asp.Net Core中,主要是基於IDistributedCache接口來實現分布式緩存服務。
3.緩存方法介紹
來自於IDistributedCache接口和DistributedCacheExtensions擴展類。
A. 讀取:Get、GetString及其對應的異步方法。根據key鍵獲取對應的值,Get方法返回的byte數組,這里更常用GetString方法,返回字符串。
B. 寫入:Set、SetString及其對應的異步方法。同上,Set操控的是byte數組,這里更常用SetString方法。DistributedCacheEntryOptions,用於配置緩存的性質,下面詳細介紹。
C. 移除:Remove及其對應的異步方法。根據key鍵來移除緩存。
D. 刷新重置:Refresh及其對應的異步方法。刷新緩存基於其密鑰,重置其滑動到期超時值(如果有)中的項。
4. 緩存性質介紹
這里通過DistributedCacheEntryOptions類配置,通過F12觀察代碼可知,可以設置以下三個屬性。
A. DateTimeOffset? AbsoluteExpiration:絕對過期時間,如: new DateTimeOffset(DateTime.Parse("2019-07-16 16:33:10"));
B. TimeSpan? AbsoluteExpirationRelativeToNow:絕對過期時間,如: TimeSpan.FromSeconds(10);
C. TimeSpan? SlidingExpiration:相對過期時間,如: TimeSpan.FromSeconds(10);
二. SqlServer分布式緩存
1. 前提
安裝【Microsoft.Extensions.Caching.SqlServer】程序集,如果是Core MVC程序,自帶的Microsoft.AspNetCore.App包里已經涵蓋了該程序集,無需重復安裝。
2. 使用步驟
A. 在數據庫中新建一個名叫“CacheDB”表,然后以管理員身份cmd運行下面指令,會創建一張名叫“AspNetCoreCache”表,相應的緩存信息都存在於這張表中。
【dotnet sql-cache create "Server=localhost;User=sa;Password=123456;Database=CacheDB" dbo AspNetCoreCache】成功后會提示:Table and index were created successfully.
PS:補充表的結構和含義, 分別是鍵、值、到期時刻(有問題)、滑動過期時間、絕對過期時間。
B. 在ConfigureService中通過AddDistributedSqlServerCache方法注冊SqlServer緩存服務,可以通過SqlServerCacheOptions對象全局配置緩存的性質。
(PS:也可以使用的時候通過DistributedCacheEntryOptions類配置)
1 { 2 "Logging": { 3 "LogLevel": { 4 "Default": "Warning" 5 } 6 }, 7 "AllowedHosts": "*", 8 "SqlSeverConnectionString": "Server=localhost;User=sa;Password=123456;Database=CacheDB", 9 //暫時沒用到,使用Redis的時候,沒有設置密碼 10 "RedisConnectionString": "172.16.1.250:6379,defaultDatabase=11,name=TestDb,password=Gworld2017,abortConnect=false" 11 }
1 //注冊分布式的SQLServer緩存服務 2 services.AddDistributedSqlServerCache(options => 3 { 4 options.ConnectionString = Configuration["SqlSeverConnectionString"]; 5 options.SchemaName = "dbo"; 6 options.TableName = "AspNetCoreCache"; 7 });
C. 通過構造函數注入IDistributedCache對象
1 public class ThirdController : Controller 2 { 3 public IDistributedCache _cache1 { get; set; } 4 5 public ThirdController(IDistributedCache cache1) 6 { 7 _cache1 = cache1; 8 } 9 }
D. 通過GetString和SetString進行讀取和寫入,通過DistributedCacheEntryOptions類配置。
1 public IActionResult Index() 2 { 3 4 string nowTime = _cache1.GetString("t1"); 5 if (string.IsNullOrEmpty(nowTime)) 6 { 7 nowTime = DateTime.Now.ToString(); 8 9 DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); 10 //1.相對過期時間 11 //options.SlidingExpiration = TimeSpan.FromSeconds(10); 12 13 //2. 絕對過期時間(兩種形式) 14 options.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(100); 15 //options.AbsoluteExpiration= new DateTimeOffset(DateTime.Parse("2019-07-16 16:33:10")); 16 17 _cache1.SetString("t1", nowTime,options); 18 } 19 ViewBag.t1 = nowTime; 20 21 return View(); 22 }
4. 緩存性質的配置
(1) 全局配置
注冊的時候通過SqlServerCacheOptions類配置,如下圖,必須要配置的三個屬性是:ConnectionString數據連接字符串、SchemaName表架構、Table表名稱。
(2) 使用時配置
通過DistributedCacheEntryOptions類配置,上面已經介紹了。
5. 擴展緩存清除相關問題
在緩存過期后,每次調用 Get/GetAsync 方法都會 調用 SqlServerCache 的 私有方法 ScanForExpiredItemsIfRequired() 進行一次掃描, 然后清除所有過期的緩存條目,掃描方法執行過程也很簡單,就是直接執行數據庫查詢語句 DELETE FROM {0} WHERE @UtcNow > ExpiresAtTime .
特別注意:異步方法中同步調用會導致過期的緩存清除不了,所以使用異步的話就異步到底。 await this.cache.GetStringAsync("CurrentTime");
三. Redis分布式緩存
1. 前提
安裝【Microsoft.Extensions.Caching.StackExchangeRedis】程序集,Core MVC中這個也是不包含的。
2. 使用步驟
A. 下載Redis程序,打開redis-server.exe,啟動Redis。
B. 在ConfigureService中通過AddStackExchangeRedisCache方法注冊Redis緩存服務。 必須要設置的是Configuration連接字符串和InstanceName實例名。
1 //注冊分布式的Redis緩存服務 2 services.AddStackExchangeRedisCache(options => 3 { 4 options.Configuration = "localhost"; 5 options.InstanceName = "SampleInstance"; 6 });
C. 通過構造函數注入IDistributedCache對象。
D. 通過GetString和SetString進行讀取和寫入,通過DistributedCacheEntryOptions類配置。
C D 兩步代碼和上述SqlServer的完全相同。
1 public class ThirdController : Controller 2 { 3 public IDistributedCache _cache1 { get; set; } 4 5 public ThirdController(IDistributedCache cache1) 6 { 7 _cache1 = cache1; 8 } 9 10 public IActionResult Index() 11 { 12 13 string nowTime = _cache1.GetString("t1"); 14 if (string.IsNullOrEmpty(nowTime)) 15 { 16 nowTime = DateTime.Now.ToString(); 17 18 DistributedCacheEntryOptions options = new DistributedCacheEntryOptions(); 19 //1.相對過期時間 20 //options.SlidingExpiration = TimeSpan.FromSeconds(10); 21 22 //2. 絕對過期時間(兩種形式) 23 options.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(100); 24 //options.AbsoluteExpiration= new DateTimeOffset(DateTime.Parse("2019-07-16 16:33:10")); 25 26 _cache1.SetString("t1", nowTime,options); 27 } 28 ViewBag.t1 = nowTime; 29 30 return View(); 31 } 32 }
3. 緩存方法和緩存性質
同SqlServer中相同的完全相同
4. 緩存清除與SqlServer的區別
使用 Redis 分布式緩存允許你在異步方法中調用同步獲取緩存的方法,這不會導致緩存清理的問題,因為緩存的管理已經完全交給了 Redis 客戶端 StackExchange.Redis了
5. 總結
細心的你可能已經發現了,上面的這段代碼和之前演示的 SqlServerCache 完全一致,是的,僅僅是修改一下ConfigureService注冊的方法,我們就能在項目中進行無縫的切換;但是,對於緩存有強依賴的業務,建議還是需要做好緩存遷移,確保項目能夠平滑過渡。
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。