ASP.net Cache丟失的問題診斷


1 業務需求

    緩存來自數據庫的數據,不用頻繁到數據庫中加載。

2 使用模型

    添加一個類 MyCache,然后在里面添加靜態屬性字段:

    public static DataTable FolderData
    {
        get
        {
            string key = "FolderData";
            object o = HttpRuntime.Cache[key];
            if (o == null)
            {
                //從DB中加載數據
                o = LoadFromDB();
                //添加到緩存中(分鍾過期)
                HttpRuntime.Cache.Insert(key, o, null,
                    System.Web.Caching.Cache.NoAbsoluteExpiration,
                    TimeSpan.FromMinutes(30));
            }
            return (DataTable)o;
        }
    }

邏輯是取數據時如果沒有,則去數據庫中加載,然后添加到緩存中以便下次使用。

前台調用時直接用MyCache. FolderData即可。

3 運行的問題

    運行一段時間后,通過后台數據庫的監控,發現有一台Web服務器還是有多次加載的SQL發送到數據庫的情況,而且發生的還很頻繁。為什么緩存沒有生效呢?丟了?添加監控日志:

 

    public static DataTable FolderData
    {
        get
        {
            string key = "FolderData";
            object o = HttpRuntime.Cache[key];
            if (o == null)
            {
                //從DB中加載數據 
                o = LoadFromDB();
                saveLog("Add to Cache Key:" + key);
                //添加到緩存中(分鍾過期)(指定回調函數) 
                HttpRuntime.Cache.Insert(key, o, null,
                System.Web.Caching.Cache.NoAbsoluteExpiration,
                TimeSpan.FromMinutes(30),
                CacheItemPriority.Normal, ASPCacheRemoveCallBack);
            }
            return (DataTable)o;
        }
    } 

   A 添加進入Cache時,記錄日志。

    B 添加刪除的回調函數,當緩存被刪除時,記錄日志。

    private static void ASPCacheRemoveCallBack
    (string key, object value, CacheItemRemovedReason reason)
    {
        saveLog("Key:" + key + "被刪除,原因:" + reason + ",時間:" + DateTime.Now.ToString());
    }

     然后分析這些日志,發現緩存有多次被刪除,刪除的原因是UnderUsed。

// 摘要:

// 之所以從緩存中移除該項,是因為系統要通過移除該項來釋放內存。

Underused = 3,

但是連上服務器看,實際內存還有很多。(系統一共16G,使用的才11.5G,而且w3wp.exe進程才占用500MB。

    為什么還有很多內存剩余,但是卻說內存不夠要把緩存的數據清理掉呢?因為是緩存,目的是少去數據庫,緩存的東西如果多了,占用內存大了,OS不是還有虛擬內存嗎?可以交換到硬盤呀,當然,如果這種情況發生,我們就把緩存的過期時間設小一點,少緩存點數據,維持系統平衡。但是不能還剩下4~5G的時候就不緩存了呀。

    添加可用的日志:

    private static void ASPCacheRemoveCallBack
    (string key, object value, CacheItemRemovedReason reason)
    {
        saveLog("Key:" + key + "被刪除,原因:" + reason + ",時間:" + DateTime.Now.ToString()
        + "可用數:" + HttpRuntime.Cache.EffectivePrivateBytesLimit);
    } 

 

查看日志,發現EffectivePrivateBytesLimit的值是0.

查閱資料:

http://msdn.microsoft.com/zh-SG/library/system.web.caching.cache.effectiveprivatebyteslimit(v=vs.80)

EffectivePrivateBytesLimit 屬性返回應用程序進程可使用的千字節數。達到此限制后,緩存算法開始積極清理緩存。

可使用應用程序配置文件中的 caching cache 元素(ASP.NET 設置架構) 元素的 privateBytesLimit 屬性 (Attribute) 設置 EffectivePrivateBytesLimit 屬性 (Property)。未設置 privateBytesLimit 屬性時,緩存算法將確定緩存的最大大小,EffectivePrivateBytesLimit 屬性將包含該算法所選擇的大小。

 為0表示ASP.net 認為沒有可分配的內存了嗎?實際情況並不是這樣,系統剛運行一個緩存也沒有時,它也是輸出0。

    進一步查看Web.Config,我們並沒有設定privateBytesLimit屬性的值。

IIS上設定了最大內存限制嗎?

也沒有設定內存的限制,而且也沒有設定要定時回收進程,這點可以從Application的變量沒有重新初始化丟失得到驗證。

同樣的程序部署運行在另外好幾套環境,EffectivePrivateBytesLimit的值也是0,但是它們沒有頻繁發生UnderUsed的情況。所以EffectivePrivateBytesLimit的值為0並不代表沒有內存可用了,需要清理,反而更像沒有對此屬性做設定的意思。

    那到底是什么原因引起的ASP.net 的清理內存呢?

    繼續查閱資料:http://msdn.microsoft.com/zh-cn/library/ms228248%28v=vs.100%29.aspx

    發現可以有幾個設定來控制緩存的設定:

根據實際運行情況, 我們猜想:ASP.net 面臨內存壓力時好像算錯了,好吧,我們讓它不要算了,只要清理過期的數據就好了。把disableMemoryCollection設定為true,告訴ASP.net面臨內存壓力時不要回收內存。

連續運行3天,ASP.net 正常清理過期的數據,但是沒有再出現刪除原因為UnderUsed的日志,內存占用也穩定,沒有大的波動。

4 結語

本來還想繼續深入尋找ASP.net Cache的緩存的清理內存機制到底是什么,到底為什么出問題,初步反射了下它的代碼,沒有准確找到,再說這個問題是 MS搞出來的,負責人應該是它,不應該我們幫它排錯(哈哈,偷懶的借口,不過每個人的精力是有限的,要解決回答為什么的問題是無限的。。。)

本文最終的結論就是設定了一個配置值而已,這么小的事似乎沒必要發Blog,但是發現大批提到UnderUsed和disableMemoryCollection的文章都只有1句話的解釋,沒有詳細的分析排錯的過程,故而獻丑寫一篇,如有不對,還請大家指出,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM