在咱們開發的不少分佈式項目裏面(如基於WCF服務、Web API服務方式),因爲數據提供涉及到數據庫的相關操做,若是客戶端的併發數量超過必定的數量,那麼數據庫的請求處理則以爆發式增加,若是數據庫服務器沒法快速處理這些併發請求,那麼將會增長客戶端的請求時間,嚴重者可能致使數據庫服務或者應用服務直接癱瘓。緩存方案就是爲這個而誕生,隨着緩存的引入,能夠把數據庫的IO耗時操做,轉換爲內存數據的快速響應操做,或者把整個頁面緩存到緩存系統裏面。緩存框架在各個平臺裏面都有不少的實現,基本上多數是採用分佈式緩存Redis、Memcached來實現。本系列文章介紹在.NET平臺中,使用開源緩存框架CacheManager來實現數據的緩存的整個過程,本篇主要介紹CacheManager的使用和相關的測試。html
CacheManager是一個以C#語言開發的開源.Net緩存框架抽象層。它不是具體的緩存實現,但它支持多種緩存提供者(如Redis、Memcached等)並提供不少高級特性。
CacheManager 主要的目的使開發者更容易處理各類複雜的緩存場景,使用CacheManager能夠實現多層的緩存,讓進程內緩存在分佈式緩存以前,且僅需幾行代碼來處理。
CacheManager 不只僅是一個接口去統一不一樣緩存提供者的編程模型,它使咱們在一個項目裏面改變緩存策略變得很是容易,同時也提供更多的特性:如緩存同步、併發更新、序列號、事件處理、性能計算等等,開發人員能夠在須要的時候選擇這些特性。git
CacheManager的GitHub源碼地址爲:https://github.com/MichaCo/CacheManager,若是須要具體的Demo及說明,能夠訪問其官網:http://cachemanager.net/。github
使用Nuget爲項目添加CacheManager包引用。CacheManager包含了不少的Package. 其中CacheManager.Core是必須的,其它的針對不一樣緩存平臺上有不一樣的對應Package,整個Nuget包包含下面幾個部分的內容。redis
CacheManager緩存框架支持Winform和Web等應用開發,以及支持多種流行的緩存實現,如MemoryCache、Redis、Memcached、Couchbase、System.Web.Caching等。數據庫
縱觀整個緩存框架,它的特定很明顯,在支持多種緩存實現外,自己主要是之內存緩存(進程內)爲主,其餘分佈式緩存爲輔的多層緩存架構方式,以達到快速命中和處理的機制,它們內部有相關的消息處理,使得即便是分佈式緩存,也可以及時實現併發同步的緩存處理。編程
在網上充斥着基於某種單獨緩存的實現和應用的趨勢下,這種更抽象一層,以及提供更高級特性的緩存框架,在提供了統一編程模型的基礎上,也實現了很是強大的兼容性,使得我一接觸到這個框架,就對它愛不釋手。緩存
在GitHub上,緩存框架的前幾名,除了這個緩存框架外,也還有一些,不過從文檔的豐富程度等各方面來看,這個緩存框架仍是很是值得擁有的。服務器
CacheManager緩存框架在配置方面,支持代碼方式的配置、XML配置,以及JSON格式的配置處理,很是方便。架構
CacheManager緩存框架默認對緩存數據的序列化是採用二進制方式,同時也支持多種自定義序列化的方式,如基於JOSN.NET的JSON序列化或者自定義序列化方式。併發
CacheManager緩存框架能夠對緩存記錄的增長、刪除、更新等相關事件進行記錄。
CacheManager緩存框架的緩存數據是強類型的,能夠支持各類常規類型的處理,如Int、String、List類型等各類基礎類型,以及可序列號的各類對象及列表對象。
CacheManager緩存框架支持多層的緩存實現,內部良好的機制能夠高效、及時的同步好各層緩存的數據。
CacheManager緩存框架支持對各類操做的日誌記錄。
CacheManager緩存框架在分佈式緩存實現中支持對更新的鎖定和事務處理,讓緩存保持更好的同步處理,內部機制實現版本衝突處理。
CacheManager緩存框架支持兩種緩存過時的處理,如絕對時間的過時處理,以及固定時段的過時處理,是咱們處理緩存過時更加方便。
....
不少特性基本上覆蓋了緩存的常規特性,並且提供的接口基本上也是咱們所常常用的Add、Put、Update、Remove等接口,使用起來也很是方便。
經過上面對CacheManager緩存框架的簡單瞭解,咱們大概瞭解了它應用的一些功能,可是實際上咱們如何使用它,咱們須要作一些學習和了解,首先咱們須要在整個應用框架裏面,知道緩存框架所扮演的角色。
通常來講,對於單機版本的應用場景,基本上是無需引入這種緩存框架的,由於客戶端的併發量不多,並且數據請求也是寥寥可數的,性能方便不會有任何問題。
若是對於分佈式的應用系統,如我在不少隨筆中介紹到個人《混合式開發框架》、《Web開發框架》,因爲數據請求是併發量隨着用戶增加而增加的,特別對於一些互聯網的應用系統,極端狀況下某個時間點一下可能就會達到了整個應用併發的峯值。那麼這種分佈式的系統架構,引入數據緩存來下降IO的併發數,把耗時請求轉換爲內存的高速請求,能夠極大程度的下降系統宕機的風險。
咱們以基於常規的Web API層來構建應用框架爲例,整個數據緩存層,應該是在Web API層之下、業務實現層之上的一個層,以下所示。
在這個數據緩存層裏面,咱們引入了CacheManager緩存框架,實現分佈式的緩存處理,使得咱們的緩存數據可以在Redis服務器上實現數據的處理,同時能夠在系統重啓的時候,不至於丟失數據,可以快速恢復緩存數據。
爲了實現對這個CacheManager緩存框架的使用,咱們須要先進行一個使用測試,以便了解它的各個方便狀況,而後才能普遍應用在咱們的數據中間層上。
咱們創建一個項目,並在引用的地方打開管理NuGet程序包,而後搜索到CacheManager的相關模塊應用,並加入到項目引用裏面,此爲第一步工做。
咱們建立一個客戶對象類,用來模擬數據的存儲和顯示的,以下代碼所示。
/// <summary> /// 模擬數據存儲的客戶對象類 /// </summary> public class Customer { private static Customer m_Customer = null; private static ICacheManager<object> manager = null; //初始化列表值 private static List<string> list = new List<string>() { "123", "456", "789" }; /// <summary> /// 客戶對象的單件實例 /// </summary> public static Customer Instance { get { if(m_Customer == null) { m_Customer = new Customer(); } if (manager == null) { manager = CacheFactory.Build("getStartedCache", settings => { settings.WithSystemRuntimeCacheHandle("handleName"); }); } return m_Customer; } }
這個類先作了一個單例的實現,並初始化緩存Customer類對象,以及緩存管理類ICacheManager<object> manager,這個是咱們後面用來操做緩存數據的主要引用對象。
咱們編寫幾個函數,用來實現對數據的獲取,數據增長、數據刪除的相關操做,並在數據增長、刪除的時候,觸發緩存的更新,這樣咱們下次獲取數據的時候,就是最新的數據了。
/// <summary> /// 獲取全部客戶信息 /// </summary> /// <returns></returns> public List<string> GetAll() { var value = manager.Get("GetAll") as List<string>; if(value == null) { value = list;//初始化並加入緩存 manager.Add("GetAll", value); Debug.WriteLine("初始化並加入列表"); } else { Debug.WriteLine("訪問緩存獲取:{0}", DateTime.Now); } return value; } /// <summary> /// 插入新的記錄 /// </summary> /// <param name="customer"></param> /// <returns></returns> public bool Insert(string customer) { //先獲取所有記錄,而後加入記錄 if (!list.Contains(customer)) { list.Add(customer); } //從新設置緩存 manager.Update("GetAll", v => list); return true; } /// <summary> /// 刪除指定記錄 /// </summary> /// <param name="customer"></param> /// <returns></returns> public bool Delete(string customer) { if(list.Contains(customer)) { list.Remove(customer); } manager.Update("GetAll", v=>list); return true; }
咱們編寫一個Winform程序來對這個緩存測試,以方便了解其中的機制。
咱們在測試讀取的時候,也就是對GetAll進行處理,插入以及刪除主要就是爲了測試緩存更新的處理。代碼以下所示。
private void btnTestSimple_Click(object sender, EventArgs e) { var list = Customer.Instance.GetAll(); Debug.WriteLine("客戶端獲取記錄數:{0}", list != null ? list.Count : 0); } private void btnInsert_Click(object sender, EventArgs e) { var name = "abc"; Customer.Instance.Insert(name); Debug.WriteLine(string.Format("插入記錄:{0}", name)); } private void btnDelete_Click(object sender, EventArgs e) { var name = "abc"; Customer.Instance.Delete(name); Debug.WriteLine(string.Format("刪除記錄:{0}", name)); }
咱們跟蹤記錄,能夠看到下面的日誌信息。
咱們能夠看到,其中第一次是緩存沒有的狀況下進行初始化,初始化的記錄數量爲3個,而後插入記錄後,再次獲取數據的時候,緩存更新後的數量就變爲4個了。
咱們前面介紹了插入記錄的後臺代碼,它同時進行了緩存數據的更新了。
/// <summary> /// 插入新的記錄 /// </summary> /// <param name="customer"></param> /// <returns></returns> public bool Insert(string customer) { //先獲取所有記錄,而後加入記錄 if (!list.Contains(customer)) { list.Add(customer); } //從新設置緩存 manager.Update("GetAll", v => list); return true; }
咱們前面介紹的緩存初始化配置的時候,默認是使用內存緩存的,並無使用分佈式緩存的配置,它的初始化代碼以下:
manager = CacheFactory.Build("getStartedCache", settings => { settings.WithSystemRuntimeCacheHandle("handleName"); });
咱們在正常狀況下,仍是須要使用這個強大的分佈式緩存的,例如咱們可使用Redis的緩存處理,關於Redis的安裝和使用,請參考個人隨筆《基於C#的MongoDB數據庫開發應用(4)--Redis的安裝及使用》。
引入分佈式的Redis緩存實現,咱們的配置代碼只須要作必定的改變便可,以下所示。
manager = CacheFactory.Build("getStartedCache", settings => { settings.WithSystemRuntimeCacheHandle("handleName") .And .WithRedisConfiguration("redis", config => { config.WithAllowAdmin() .WithDatabase(0) .WithEndpoint("localhost", 6379); }) .WithMaxRetries(100) .WithRetryTimeout(50) .WithRedisBackplane("redis") .WithRedisCacheHandle("redis", true) ; });
其餘的使用沒有任何變化,咱們同時增長一些測試數據方便咱們查閱對應的緩存數據。
/// <summary> /// 測試加入幾個不一樣的數據 /// </summary> /// <returns></returns> public void TestCache() { manager.Put("string", "abcdefg"); manager.Put("int", 2016); manager.Put("decimal", 2016.9M); manager.Put("date", DateTime.Now); manager.Put("object", new UserInfo { ID = "123", Name = "Test", Age = 35 }); }
private void btnTestSimple_Click(object sender, EventArgs e) { var list = Customer.Instance.GetAll(); Debug.WriteLine("客戶端獲取記錄數:{0}", list != null ? list.Count : 0); //測試加入一些值 Customer.Instance.TestCache(); }
咱們其中測試,一切和原來沒有什麼差別,程序的記錄信息正常。
可是咱們配置使用了Redis的緩存處理,所以可使用「Redis Desktop Manager」軟件來查看對應的緩存數據的,打開軟件咱們能夠看到對應的緩存記錄以下所示。
從上圖咱們能夠查看到,咱們添加的全部緩存鍵值均可以經過這個Redis的客戶來進行查看,由於咱們緩存裏面有基於Redis緩存的實現,同理若是咱們配置其餘的緩存實現,如MemCache等,那麼也能夠在對應的管理界面上查看到。
咱們完成這些處理後,能夠發現緩存數據是能夠實現多層緩存的,最爲高效的就是內存緩存(也是它的主緩存),它會自動協同好各個分佈式緩存的數據版本衝突問題。
引入如Redis的分佈式緩存有一個好處,就是咱們的數據能夠在程序從新啓動的時候,若是沒有在內存緩存裏面找到(沒有擊中目標),那麼會尋找分佈式緩存並進行加載,從而即便程序重啓,咱們以前的緩存數據依舊保存無缺。
以上就是我基於對緩存框架的總體瞭解和其角色扮演作的相關介紹,以及介紹CacheManager的使用和一些場景的說明,經過上面簡單案例的研究,咱們能夠逐步引入到更具實際價值的Web API 框架層面上進行使用,以期把緩存框架發揮其真正強大的價值,同時也爲咱們各類不一樣的緩存須要進行更高層次的探索,但願你們繼續支持。