不應(yīng)該被其它用戶訪問的特定于Session的數(shù)據(jù)。
緩存架構(gòu)
有很多種對象緩存架構(gòu)(包括開放源代碼的和商業(yè)的實現(xiàn))在servlet容器和應(yīng)用服務(wù)器中提供了分布式緩存。下面列出了一些現(xiàn)在可以使用的緩存框架:
開放源代碼項目
商業(yè)項目
如果你還有興趣了解更多的緩存實現(xiàn),本文最后的資源一節(jié)提供了所有這些框架的URL。
我在最初開始我對能滿足我們所有的緩存需求的框架進行研究的時候,我先看到了Commons Collections 和 Java Caching System API 。我在最開始評估的主要標準就是容易使用、容易擴展,以及軟件的成本。這兩個框架都是開放源代碼的,并且都來自于Apache Jakarta項目。
Commons Collections
Commons Collections API 以一個Java類的形式提供了對象緩存算法,名稱為LRUMap。如果你對緩存只有基本的需求,并且不是真正需要很多的擴展和緩存配置功能,那么Commons Collections 可能是一個不壞的選擇,但不是作為一個企業(yè)級緩存系統(tǒng)的正確選擇。如果你選擇Common Collections來實現(xiàn)對象緩存,你將會手工定義/配置所有的緩存參數(shù),如:最大緩存對象的數(shù)量,一個緩存對象的最長生命周期,刷新緩存或檢查對象新鮮的中斷時間等。
Java Caching System
Java Caching System (JCS), Jakarta Turbine 項目的一部分, 與Commons Collections相比更有成熟、更具擴展性。通過為頻繁訪問的對象維護動態(tài)對象池的方法,它提供了提升整個系統(tǒng)性能的靈活、可配置的解決方案。就像在它的網(wǎng)站上提到的,JCS 已經(jīng)超越了簡單地在內(nèi)存中緩存對象的范圍。它為一個企業(yè)級的緩存系統(tǒng)提供了許多必需的重要功能:
JCS 提供了無故障點的框架, 允許完全的session失敗轉(zhuǎn)移(在集群環(huán)境中),包括支持最多到256個服務(wù)器的session數(shù)據(jù)分布。它也提供了配置一個或多個數(shù)據(jù)存儲選項的靈活性,例如:內(nèi)存緩存、磁盤緩存,或者在遠程機器上的緩存。
所有這些包括在JCS中的優(yōu)秀功能讓它成為滿足我們的web門戶項目的一個優(yōu)秀的對象緩存產(chǎn)品選擇
使用JCS構(gòu)造Web 門戶緩存框架
緩存框架的目標
在開始設(shè)計對象緩存框架之前,首先列出了在新的框架中需要達到的目標。以下就是目標的列表:
安裝和配置
在web應(yīng)用中安裝和配置JCS是非常簡單的事情。從Jakarta Turbine網(wǎng)站下載壓縮文件,解壓縮文件到臨時目錄,并拷貝JSC.jar文件(jcs-1.0-dev.jar)到servlet容器的通用目錄(在我的web應(yīng)用中使用的servlet容器是Tomcat,通用目錄在windows下就是%TOMCAT_HOME%\common\lib,在再Unix類型的系統(tǒng)下就是$TOMCAT_HOME/common/lib)。你可能還需要commons-collections.jar, commons-lang.jar, 和 commons-logging.jar 這些文件存在于web應(yīng)用的類路徑下以便使用JCS。
對象緩存框架的主要原理在圖1和圖2的UML圖中展示出來了
框架的主要原理
緩存屬性
我們將所有的緩存參數(shù)配置在名為cache.ccf的屬性文件中。這些參數(shù)包括緩存信息如:內(nèi)存中存儲的對象的最大數(shù)量,緩存時間(過了時間之后緩存的數(shù)據(jù)九自動從內(nèi)存中釋放),中斷時間(elapsed time since last access time), 內(nèi)存緩存名稱(例如:緩存算法如LRU或MRU)等。在當前版本的JCS中,緩存屬性文件是純文本格式的。SpiritCache framework,一種來自SpiritSoft的Jcache API商業(yè)實現(xiàn),支持XML格式的緩存配置。
確認該屬性文件存放在類路徑中。注意:如果你需要使用其它不同的文件來存放緩存屬性的話,JCS 也提供了方法來指定一個配置文件的名稱。請參考JCS的 Javadocs 學(xué)習(xí)如
下面列出來的是web應(yīng)用使用緩存功能需要了解的一些Java類。這些類存放在本文的示例代碼的common.caching包中。這些類的Javadocs也包括在源代碼壓縮包中。 (圖2 中的類圖顯示了這些Java類的關(guān)系)
ICacheManager
這是客戶應(yīng)用實現(xiàn)所有緩存有關(guān)操作(如:存儲、訪問以及釋放緩存中的數(shù)據(jù))的主接口(契約)??蛻舫绦蚩梢允荍SP、Struts Action類,或者就是一個POJO對象。創(chuàng)建該接口用于對客戶端隱藏所有緩存的實現(xiàn)細節(jié),這樣當我們將來需要切換另一種的第三方緩存API的時候無需對客戶端代碼做任
BaseCacheManager
這是web門戶緩存框架的主類。是對ICacheManager 接口的最基本實現(xiàn)。創(chuàng)建BaseCacheManager 用于在一個類中集中所有緩存相關(guān)的方法。它被設(shè)計為單例模式保證在servlet容器的JVM中有且僅有一個ICacheManager 的實例被創(chuàng)建。在多web服務(wù)器/servlet容器實例共同處理web請求的集群環(huán)境中,每個JVM將會創(chuàng)建獨立的ICacheManager 實例。如果將來你要轉(zhuǎn)換到不同的緩存API ,這是唯一需要為新的緩存API修改的類。如果你切換到JCache-兼容的緩存實現(xiàn),對緩存管理器的修改將會是很小的。
ICacheLoader
該接口用于在web客戶端實現(xiàn)真正的數(shù)據(jù)訪問邏輯。所有需要使用緩存機制的客戶端應(yīng)用必須實現(xiàn)該接口。它包括僅有的一個方法叫做loadCacheObject() ,有兩個輸入?yún)?shù):一個String參數(shù)制定緩存區(qū)域名稱,一個對象參數(shù)制定緩存鍵值。這樣,緩存管理器將知道在緩存的對象超過指定的“生存時間”的時候,使用哪個客戶端程序(運行l(wèi)oadCacheObject 方法)來重載緩存中的對象 。
ICacheKey
ICacheKey 接口創(chuàng)建的目的是為了隱藏特定的創(chuàng)建緩存鍵值的細節(jié)。有時候緩存的鍵值不是一個簡單的字符串。它可能像多個對象組合起來一樣復(fù)雜,從數(shù)據(jù)源獲取這些值需要多個查找方法而不是單一的方法。在這種情況下, ICacheKey 接口可以被用來定義創(chuàng)建緩存鍵值的所有復(fù)雜的邏輯。這樣,緩存鍵值創(chuàng)建邏輯將會被定義為獨立的類。我編寫了一個簡單的類TestCacheKey 實現(xiàn)了該接口并實現(xiàn)了getCacheKey() 方法來演示使用該接口的方法。
CacheRegions
一個 緩存區(qū)域 被定義為一個組織起來的命名空間用于容納一組緩存對象集合。你需要在配置文件中定義緩存區(qū)域來實現(xiàn)在一塊單獨的內(nèi)存空間中存儲數(shù)據(jù),管理緩存數(shù)據(jù)的有效期限。如果需要的話,對有相似特征的對象(例如:生存時間和業(yè)務(wù)用途)應(yīng)該被緩存在相同的緩存區(qū)域中,讓它們可以在相同的時間失效。我定義了分離的緩存區(qū)域來存儲靜態(tài)數(shù)據(jù)和小變動數(shù)據(jù)。為了避免同步操作帶來的效率影響,我對每個緩存區(qū)域使用了單獨的Cache (JCS) 實例。
CacheElementInfo
該類用于封裝所有的緩存統(tǒng)計信息(例如:命中數(shù)、不中數(shù)、命中比例等),用來監(jiān)測在web應(yīng)用中所有緩存對象的效率。
編譯, 構(gòu)建, 和單元測試
用Ant創(chuàng)建了一個構(gòu)建腳本來編譯我的對象緩存框架的所有代碼。Ant的構(gòu)建腳本build.xml, 放在WEB-INF\classes 目錄下。我還編寫了Junit測試客戶端來測試使用web門戶緩存框架的不同緩存場景。測試腳本CachingTestCase, 放在WEB-INF\classes\common\caching\test 目錄下。解壓縮示例代碼到一個新的web應(yīng)用目錄,如果要驗證Junit測試腳本,從命令行運行以下命令:
切換當前目錄到%TOMCAT_HOME%/webapps/web-app-name/WEB-INF/classes (在Unix測試環(huán)境中,目錄應(yīng)該是$TOMCAT_HOME/webapps/web-app-name/WEB-INF/classes)。
運行以下命令:
考慮
當你決定要在你的web應(yīng)用中緩存一些特定類別的數(shù)據(jù)的時候,請參照這些指導(dǎo)方針。緩存的應(yīng)用應(yīng)該經(jīng)過謹慎地考慮,只有當其它方法,如:數(shù)據(jù)訪問等,已經(jīng)無法再進一步改進的時候才需要使用緩存。緩存將會帶來復(fù)雜性,讓維護工作變得更加復(fù)雜。因此,必須統(tǒng)籌考慮性能和緩存帶來的復(fù)雜性的平衡關(guān)系。
當考慮使用緩存的時候,需要考慮對象的預(yù)定執(zhí)行時間和刷新率或者叫做對象的生存時間。緩存不能容納所有我們想要存儲的數(shù)據(jù),因此緩存使用的內(nèi)存及時得到釋放,即可以通過定義合理的生存時間實現(xiàn),也可以在數(shù)據(jù)不再需要的時候顯式地釋放被緩存的對象。可以指定緩存算法如最近被訪問算法(LRU)或者最少被使用算法(LFU)以便緩存基于訪問頻率來釋放對象。Jack Shirazi的著作 Java 性能調(diào)整 提供了一個關(guān)于緩存主題的非常有趣的討論,討論了什么類型的數(shù)據(jù)應(yīng)該被緩存,以及
注意緩存框架并沒有處理在web應(yīng)用中需要被緩存的對象的創(chuàng)建(例如:從數(shù)據(jù)源檢索數(shù)據(jù)的數(shù)據(jù)訪問邏輯并沒有在緩存類中編寫)。這要依賴于客戶程序來定義真正的數(shù)據(jù)訪問邏輯。像Java數(shù)據(jù)對象等技術(shù)通常用于在企業(yè)級web應(yīng)用中封裝數(shù)據(jù)訪問邏輯。參考O´Reilly的 Java 數(shù)據(jù)對象 來學(xué)習(xí)更多的關(guān)于如
結(jié)論
本文提供了對使用Jakarta的Java緩存系統(tǒng)(JCS)來為web門戶應(yīng)用開發(fā)對象緩存框架的概要介紹。該框架非常穩(wěn)定并可以被重用于其它任
JCS was built as a system close to JCACHE Java Temporary Caching API (JSR-107), a description of the caching system used in Oracle 9i and other popular caching frameworks. 該規(guī)范可能會在將來的JDK發(fā)行版本中作為一種Java擴展框架。我的其中一個目的就是讓web門戶緩存框架與JCS保持松散耦合。這樣的話,如果我將來需要轉(zhuǎn)換到另一種框架(例如Jcache),我可以在對web門戶應(yīng)用客戶程序代碼不做大的調(diào)整的情況下完成切換。
我現(xiàn)在通過記錄緩存監(jiān)測信息的日志(使用Log4J API)如:命中數(shù)、不中數(shù)、命中率來衡量緩存的效率??赡軐碛衅渌鼌?shù)需要被監(jiān)測來衡量緩存的效率。同樣的,用來測量使用或不使用緩存對數(shù)據(jù)訪問的反饋時間,應(yīng)該使用一些負載測試工具如:Grinder或者Jmeter來測試其伸縮性和性能效果。
在機群環(huán)境下保持緩存同步將是一個挑戰(zhàn),因為每個servlet容器將會在自己的JVM中擁有一個緩存管理器實例。解決該問題的方法就是創(chuàng)建消息驅(qū)動Bean(MDB)在需要刷新數(shù)據(jù)的時候通知所有的緩存管理器。
通常的對象查找方法,如:簡單的Hashtable、JNDI甚至是EJB,提供了在內(nèi)存中存放對象并通過鍵值查找對象的方法。但是任
雖然將緩存功能集成到web應(yīng)用中需要額外的設(shè)計和開發(fā)工作,但我認為緩存帶來的利益大于額外付出的工作。我已經(jīng)看到在我實現(xiàn)了緩存框架之后 ,我的web應(yīng)用的性能有很大的提高,特別是在訪問靜態(tài)數(shù)據(jù)和查找結(jié)果方面。該web應(yīng)用模塊目前處于測試階段。在不久的將來,我會提供一些性能方面的測試數(shù)據(jù)(包括使用與不使用緩存的情況)來比較緩存如
參考資源