[Asp.net 5] Caching-緩存架構與源碼分析

来源:http://www.cnblogs.com/watermoon2/archive/2016/01/13/5126298.html
-Advertisement-
Play Games

首先奉獻caching的開源地址[微軟源碼]1.工程架構為了提高程式效率,我們經常將一些不頻繁修改,但是使用了還很大的數據進行緩存。尤其是互聯網產品,緩存可以說是提升效率優化第一利器。微軟為我們實現了倆種緩存方式:記憶體緩存、分散式緩存。個人理解如果緩存在前端電腦記憶體的緩存叫做記憶體緩存,如果緩存在其它...


首先奉獻caching的開源地址[微軟源碼]

1.工程架構

 

為了提高程式效率,我們經常將一些不頻繁修改,但是使用了還很大的數據進行緩存。尤其是互聯網產品,緩存可以說是提升效率優化第一利器。微軟為我們實現了倆種緩存方式:記憶體緩存、分散式緩存。個人理解如果緩存在前端電腦記憶體的緩存叫做記憶體緩存,如果緩存在其它設備上,那麼叫做分散式緩存。

  • 倆種緩存方式的優缺點

  我開發程式經歷過三個時間點,開始的時候從來不使用緩存,之後將數據緩存在記憶體中,最後使用分散式緩存。記憶體緩存的優點是速度快,缺點是記憶體損耗比較大,可能緩存的數據太大的時候就放不下了,另外一個缺點就是對於多前端程式的原則上是不支持的。而分散式緩存的優點是,理論上緩存大小沒有上線,可以通過擴充物理硬體進行擴展,對於多前端支持的較好。

Microsoft.Framework.Caching.Abstractions

這個工程定義的是緩存的整體架構。我們的思想是面向介面編程,而不是面向實現編程。所以該工程定義了我們想要的介面

從上圖顯而易見,微軟將記憶體緩存和分散式緩存割裂開來,而不是我們一般意義上定義一個ICache介面,之後讓IMemoryCache和IDistributedCache分別繼承ICache介面。

所以我們用分散式緩存,記憶體緩存原則不能無縫的直接切換。需要我們修改程式代碼,或者進行適配封裝。

  • 分散式緩存

   這部分包含內容只包含簡單的倆點:配置項(DistributedCacheEntryOptions)、緩存介面(IDistributedCache)。而DistributedCacheEntryExtentions是DistributedCacheEntryOptions的擴展方法包裝類,CaceheExtensions是IDistributedCache擴展方法包裝類,CacheItemPriority是優先順序枚舉。

  • 記憶體緩存

  記憶體緩存,微軟的設計就比較複雜,考慮到方方面面。首先時緩存的配置項(IMemoryCacheEntryOptions)、緩存介面(IMemoryCache)以及它們擴展項(MemoryCacheEntryExtentions、CacheExtentions)。

  但是微軟的想法,緩存不止應該只有過期失效,當我程式update一個欄位後,我想通知記憶體緩存,我更改了,那又該怎麼辦呢?於是微軟設計了右上角的部分(*由於代碼的持續更新原因右上角部分的介面已經被去掉,由IList<IChangeToken> ExpirationTokens { get; }屬性替代,但是原則都是一樣的,即外部通知內部,數據已經更新)。

  既然外部數據更新能通知緩存,那反向呢?緩存更新是否能夠通知外部使用對象呢?答案是這個可以支持,所有上邊框,下麵的部分。

  既然能外部修改通知內部,內部修改也能通知外部應用程式。設計已經趨近完美了?微軟說還不夠,於是上圖左邊的部分產生了。它的意義就是,我可以為緩存創建一個範圍,至於範圍是做什麼的?答案是“我也不知道”,但是從記憶體緩存的實現上來看,是用於整體緩存token等信息的。

  緩存配置項的時間選項:AbsoluteExpiration、AbsoluteExpirationRelativeToNow、SlidingExpiration。分別表示的是絕對的過期時間點、相對於現在多久的絕對過期時間點,有效期時長。我們註意下類型AbsoluteExpiration是DateTimeOffset不是DateTime。(*DateTimeOffset 是對於1970年1月1日0時的時間偏移量,和DateTime相比,缺少時區的概念。而此處不需要有時區相關概念,所以選用了DateTimeOffset )。

 

 Microsoft.Extensions.Caching.Memory

  記憶體緩存的實現。此處代碼結構如下圖所示:

  • 大邏輯

  1,緩存太大時,壓縮緩存空間(個人理解)

  系統創建記憶體緩存對象(MemoryCache)的時候,同時創建GcNotification對象,之後GcNotification對象立馬失效。GC需要析構的時候,會調用GcNotification的析構函數,析構函數被調用後會執行CallBack函數(定義在MemoryCache),之後再次註冊析構函數,迴圈往複的如此。所以當記憶體占用太高的時候,緩存會縮減緩存空間。

        if (reRegister && !Environment.HasShutdownStarted)
            {
                GC.ReRegisterForFinalize(this);
            }    
註冊析構函數

  2,緩存對象(MemoryCache)的釋放,沒有對象引用緩存的話,難免GC會回收緩存對象。那麼怎麼避免緩存被GC回收?下麵代碼的思路還是不錯的

        ~MemoryCache()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    GC.SuppressFinalize(this);
                }

                _disposed = true;
            }
        }

        private void CheckDisposed()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(typeof(MemoryCache).FullName);
            }
        }
緩存對象析構

  3,IEntryLink對象的跨線程訪問

  緩存過期的時候,很可能不是本線程訪問的,可能是另外一個線程,通過獲取IEntryLink,之後通過IChangeToken對象通知緩存,所以不同線程間必須是可以共用IEntryLink對象。此處使用的是CallContext.LogicalGetData與CallContext.LogicalSetData。關於線程見數據通信,請參考“如何實現對上下文(Context)數據的統一管理

    internal static class EntryLinkHelpers
    {
        private const string ContextLinkDataName = "EntryLinkHelpers.ContextLink";

        public static EntryLink ContextLink
        {
            get
            {
                var handle = CallContext.LogicalGetData(ContextLinkDataName) as ObjectHandle;

                if (handle == null)
                {
                    return null;
                }

                return handle.Unwrap() as EntryLink;
            }
            set
            {
                CallContext.LogicalSetData(ContextLinkDataName, new ObjectHandle(value));
            }
        }

        internal static IEntryLink CreateLinkingScope()
        {
            var parentLink = ContextLink;
            var newLink = new EntryLink(parent: parentLink);
            ContextLink = newLink;
            return newLink;
        }

        internal static void DisposeLinkingScope()
        {
            var currentLink = ContextLink;
            var priorLink = ((EntryLink)currentLink).Parent;
            ContextLink = priorLink;
        }
    }
EntryLinkHelpers代碼示例

 

 

未完待續......


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 您可能聽說過,帶有 yield 的函數在 Python 中被稱之為 generator(生成器),何謂 generator ?我們先拋開 generator,以一個常見的編程題目來展示 yield 的概念。如何生成斐波那契數列斐波那契(Fibonacci)數列是一個非常簡單的遞歸數列,除第一個和第二...
  • c中malloc和free是函數,包含在stdlib.h頭文件中,分配成功返回指針,失敗返回空指針。與new的區別是:1,malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用於申請動態記憶體和釋放記憶體。2,對於非內部數據類型的對象而言,光用maloc/f...
  • STM32定時器功能強大,共有8個16位定時器,其中TIM6、TIM7為基本定時器,主要產生DAC觸發信號;TIM2、TIM3、TIM4、TIM5為通用定時器,除了基本的定時外,主要還有幾個可用場合捕獲/比較寄存器,可實現脈衝頻率測量;PWM輸出過程分析;PWM輸入過程分析;定時器時鐘,可使用...
  • (以下為個人理解) OOP(Object OrientedProgramming)面向對象思想,主要體現為封裝、繼承、多態、虛擬函數; 封裝:將實現功能的具體方法,放到一個類中,調用的人不用知道它具體是怎麼實現功能的,只需要知道,它能實現什麼功能,參數需要什麼,以及返回值的類型,就能使用它去實現.....
  • 問題描述工作中碰到一個dt.Compute("max(lineid)","")來取最大行號的情況,由於dt中數據大概有4000條,發現每次調用需要0.3秒的耗時,耗時太長解決方法 DataView dv = dt.DefaultView; dv.Sort ...
  • Adding a New Field to the Movie Model and Table報錯
  • 最近做個項目,一直有一個問題沒有解決,就是在XP下,有的Textbox里在文本框里沒有東西的時候,會沒有游標。不同的XP機器,失去游標的Textbox也不一樣。各位大師看下麵的三張圖,當Textbox獲取焦點以後顏色就會變,第一個框和第三個框都有游標,但是第二個框沒有游標,如果向Textbox中輸入...
  • MongoDB提供的C#開發介面,先從下載開始,然後是插入、查詢、更新。先要開啟MongoDB服務。下載http://github.com/mongodb/mongo-csharp-driver/downloads.每個版本會有兩個驅動模式,一個是.msi,一個是.zip。VS:2013,Mongo...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...