一、上章回顧
上一章中我們主要簡單的介紹了如何使用服務器緩存及如何實現(xiàn)服務器緩存,下面我們來通過下圖來進行詳細回顧:
1、用戶發(fā)送頁面請求,等待服務器返回信息。
2、表示層通過請求業(yè)務層來訪問業(yè)務數(shù)據(jù)信息。
3、業(yè)務層在與數(shù)據(jù)訪問層交互時先與服務器緩存組件交互。
4、服務器緩存在接收數(shù)據(jù)請求并處理的過程中判定服務器緩存中是否存在指定的數(shù)據(jù)集緩存對象。如果存在則返回該緩存對象,否則通過數(shù)據(jù)訪問層,訪問數(shù)據(jù)庫中的數(shù)據(jù),并把數(shù)據(jù)緩存在服務器組件中。并返回該查詢結(jié)果集。
5、表示層獲得數(shù)據(jù)集合后顯示。
二、摘要
本章將主要講解緩存中的過期策略及如何平衡過期這個過期策略,怎么樣在項目中解決這樣的問題,這就是本篇要講述的內(nèi)容。
三、本章大綱
1、上章回顧。
2、摘要。
3、本章大綱。
4、具體策略分析。
5、緩存過期策略方案。
6、本章總結(jié)。
7、下篇預告。
四、具體策略分析
我們我們平時使用緩存中最頭疼的問題應該就是緩存的過期的問題吧,緩存帶來的好處顯而易見,不見提高了網(wǎng)站應用程序的性能,同時提高了訪問的速度,減少了與數(shù)據(jù)庫交互的次數(shù)。無疑是好的方案,所以網(wǎng)上有很多的建議都是,能緩存的數(shù)據(jù)盡量緩存,因為緩存必定能帶來性能的提升。同時有個很大的問題始終困擾著我們。這樣是我平時在使用緩存的過程中頭疼的問題。例如這樣的情況:
所以問題就隨之而來,如何保證這個產(chǎn)品策略的過期性和同步性,當然我們知道產(chǎn)品分類一般情況下變化不大,所以我們緩存,對于信息變化或者改變頻率較高的數(shù)據(jù),我們當然可以考慮每次加載的時候都緩存,等到第二次訪問的時候過期這樣的方式來處理也是可以的?傊鼐褪遣唤(jīng)常改變的常用的數(shù)據(jù)信息能緩存的一定緩存。大家都知道2-8法則的,其實不管是什么程序基本上都滿足這個原則。
當然Winform的程序則會比較復雜一些,可能制定的策略相對來說也不好指定。因為一般情況下來說客戶端/服務器這樣的形式,一般的數(shù)據(jù)信息都緩存在客戶端,這樣服務器壓力小一些,當然也有弊端,就是每個客戶端都是有自己的快照副本,不過由于現(xiàn)在硬件的速度發(fā)展迅速,所以這方面的力度可以考慮加大,顯而易見,當數(shù)據(jù)庫中的數(shù)據(jù)發(fā)生改變后,如何通知winform程序進行緩存更新也是個重要的問題,畢竟winform程序的緩存策略與web程序的緩存方式有所不同。當然如果說winform也是采用服務器端緩存的話,當然也可以采用上面我們討論的方式來實現(xiàn)更新策略。
下面我們來看看我理解的可操作的winform的緩存策略的更新。
當然上面只是個人愚見,不足之處還請大家多多指點。歡迎大家拍磚,下面我們來講講各種策略的實現(xiàn)及優(yōu)缺點。
五、緩存過期策略方案
上面我們簡單的分析了,winform與web應用程序的可能的緩存過期策略。下面我們來講講幾種可能的解決方案,當然只是個人愚見,還請大家拍磚,這里只是拋磚引玉,沒有考慮更復雜的情況。還請大家多多分享自己的經(jīng)驗。
1、使用微軟提供的服務器緩存的過期策略:
a、相對過期。舉個簡單例子就是,如果緩存對象在某個時間段內(nèi)沒有被訪問過,那么該對象則過期,否則則不過期。
b、絕對過期。舉個簡單例子就是,不管緩存的對象訪問沒有訪問過,只要到達設(shè)置的時間則過期。
具體的實現(xiàn)時,我們可以參考通過配置文件中設(shè)置這個過期策略,例如我們參考IBatisNet中的緩存
1 <cacheModels>//緩存的對象列表
2 <cacheModel id="CacheLRU_Sys_UserRole" implementation="LRU" >//緩存的對象
3 <flushInterval minutes="2" />//設(shè)置過期策略
4 <flushOnExecute statement="Insert_Sys_UserRole"/>//刷新的動作
5 <flushOnExecute statement="Update_Sys_UserRole"/>
6 <flushOnExecute statement="Delete_Sys_UserRole"/>
7 <property name="CacheSize" value="100"/>//設(shè)置緩存對象的大小
8 </cacheModel>
9 </cacheModels>
顯然通過上面提供的方式可以做到緩存對象的自動過期,但是有個情況就是不夠靈活,如果緩存對象在指定的時間段內(nèi)已發(fā)生改變,那么必須在過期時間后才能更新緩存對象,那么有些時候顯然不能滿足我的要求,特別是實時性的系統(tǒng)時這樣的緩存策略是不可行的。
2、當然上面介紹的IBatisNet中已包含設(shè)置刷新對象時的操作的設(shè)置:
1 <flushOnExecute statement="Insert_Sys_UserRole"/>//刷新的動作
2 <flushOnExecute statement="Update_Sys_UserRole"/>
3 <flushOnExecute statement="Delete_Sys_UserRole"/>
那么體現(xiàn)在程序中的代碼如何書寫呢,我們來看看。
01 /// <summary>
02 /// 定義委托、用于指向更新緩存的事件
03 /// </summary>
04 /// <returns>返回是否更新緩存</returns>
05 public delegate bool RefreshCache(object sender, EventArgs e);
06
07 /// <summary>
08 /// 維護緩存更新策略的委托集合
09 /// </summary>
10 public Dictionary<object, List<RefreshCache>> list;
那么通過XML配置相關(guān)的引發(fā)緩存更新的事件來達到更新緩存的目的。
那么每次委托列表中維護的對象即是所有的緩存對象的相關(guān)刷新動作事件。通過檢測事件的執(zhí)行來更新緩存對象。
具體的更新緩存的代碼如下:
1 public void RefreshCacheObject(object key,bool isSuccess)
2 {
3 if (!isSuccess)
4 return;
5 if (list.ContainsKey(key))
6 list.Remove(key);
7
8 //載入緩存
9 }
具體的載入緩存的代碼請參考:網(wǎng)站性能優(yōu)化之應用程序緩存-初篇
具體的實現(xiàn)底層通知的代碼我還沒有想好具體的實現(xiàn)方式(就是比較好的方式)。想好了會把代碼貼上,當然IBatisNet已經(jīng)很優(yōu)秀了,我這里也許沒有造輪子的必要,如果誰有比較好的實現(xiàn)方式,那么可以告訴我,我這里先謝過了,我其實不是很了解底層的實現(xiàn)機制,所以我目前只是采用比較笨的方式來做,雖然也實現(xiàn)了,但是需要在每個事件中都要顯示的寫一部分代碼,這是我不能接受的。
3、時時更新的方式。
這里的時時更新就是指,每次都把數(shù)據(jù)庫中的記錄全部取出來,然后循環(huán)比較結(jié)果集中的記錄與緩存的記錄是不是相同,如果不同則更新該記錄,否則跳過繼續(xù)處理其他的數(shù)據(jù)信息,那么保證緩存中的記錄始終是最新的。當然這樣的方式雖然保證所有的緩存信息是最新的,但是每次都與數(shù)據(jù)庫交互顯然不是好的解決方案,當然有些情況下也許也是沒有辦法的事情。
最后,本文只是拋磚引玉,希望大家多多提出寶貴意見。
六、本章總結(jié)
本文簡單的介紹了web與winform下的緩存策略,分析了幾種方式的可行性及優(yōu)缺點等,還希望大家在實際的項目中根據(jù)項目的需要來指定緩存的過期策略,但是可以肯定的是,用緩存肯定比不用緩存的性能要高。當然這里也不是要求我們?yōu)E用緩存,也要根據(jù)數(shù)據(jù)信息的更新頻度做一個平衡,不經(jīng)常變的數(shù)據(jù)一般推薦來緩存。畢竟服務器中有同一副本,不但能提高訪問的效率,還能減輕數(shù)據(jù)庫的訪問壓力,提高并發(fā)的速度。還需要大家在實際項目中體會。
七、下篇預告
本篇并沒有把IBatis.NET中的緩存策略完整的實現(xiàn),并且也沒有講到其他的一些winform的緩存策略的實現(xiàn),下一篇將會詳細的講解這部分的內(nèi)容,當然這些都是本人的個人體會與總結(jié),錯誤之處在所難免,歡迎大家提出不同意見,批評指出錯誤,謝謝大家!