.NET緩存框架CacheManager在混合式開發框架中的應用(1)-CacheManager的介紹和使用

在咱們開發的不少分佈式項目裏面(如基於WCF服務、Web API服務方式),因爲數據提供涉及到數據庫的相關操做,若是客戶端的併發數量超過必定的數量,那麼數據庫的請求處理則以爆發式增加,若是數據庫服務器沒法快速處理這些併發請求,那麼將會增長客戶端的請求時間,嚴重者可能致使數據庫服務或者應用服務直接癱瘓。緩存方案就是爲這個而誕生,隨着緩存的引入,能夠把數據庫的IO耗時操做,轉換爲內存數據的快速響應操做,或者把整個頁面緩存到緩存系統裏面。緩存框架在各個平臺裏面都有不少的實現,基本上多數是採用分佈式緩存Redis、Memcached來實現。本系列文章介紹在.NET平臺中,使用開源緩存框架CacheManager來實現數據的緩存的整個過程,本篇主要介紹CacheManager的使用和相關的測試。html

一、CacheManager的介紹

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緩存框架的應用

經過上面對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 框架層面上進行使用,以期把緩存框架發揮其真正強大的價值,同時也爲咱們各類不一樣的緩存須要進行更高層次的探索,但願你們繼續支持。

相關文章
相關標籤/搜索