<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    每日一得

    不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速開發
    最近關心的內容:SSH,seam,flex,敏捷,TDD
    本站的官方站點是:顛覆軟件

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      220 隨筆 :: 9 文章 :: 421 評論 :: 0 Trackbacks

    4? Jive 的緩存機制

    Jive 論壇的一個主要特點就是其性能速度快,因此很多巨大訪問量的網站都采用了 Jive 論壇。這些都是由于 Jive 采取了高速緩存機制。

    緩存( Cache )機制是提高系統運行性能必不可少的技術。緩存機制從原理上講比較簡單,就是在原始數據第一次讀取后保存在內存中,下次讀取時,就直接從內存中讀取。原始數據有可能保存在持久化介質或網絡上。緩存機制也是代理模式的一種實現。

    4.1? 緩存原理和實現

    Jive Cache 總體來說實現得不是非常精簡和有效。它是針對每個具體數據對象逐個實現緩沖,這種“窮盡”的辦法不是實踐所推薦的用法。通過使用動態代理模式,可以根據具體方法的不同來實現緩存是值得推薦的做法。 Jive 的緩存實現得比較簡單,可以用來學習和研究緩存機制。

    Jive 中的 Cache 實現了緩存機制的大部分行為,它是將對象用惟一的關鍵字 Key 作標識保存在 HashMap Hashtable 中。當然,必須知道這些對象的大小,這個前提條件的設定可以保證緩存增長時不會超過規定的最大值。

    如果緩存增長得太大,一些不經常被訪問的對象將首先從緩存中刪除。如果設置了對象的最大生命周期時間,即使這個對象被反復頻繁訪問,也將從緩存中刪除。這個特性可以適用于一些周期性需要刷新的數據,如來自數據庫的數據。

    Cach 中除了 getObject() 方法的性能依據緩存大小,其他方法的性能都是比較快的。一個 HashMap 用來實現快速尋找,兩個 LinkedList 中一個以一定的訪問順序來保存對象,叫 accessed LinkedList ;另外一個以它們加入緩存的順序保存這些對象,這種保存對象只是保存對象的引用,叫 age LinkedList 。注意,這里的 LinkedList 不是 JDK 中的 LinkedList ,而是 Jive 自己定義的 LinkedList

    當對象被加入緩存時,首先被 CacheObject 封裝。封裝有以下信息:對象大小(以字節計算),一個指向 accessed LinkedList 的引用,一個指向 age LinkedList 的引用。

    當從緩存中獲取一個對象如 ObjectA 時,首先, HashMap 尋找到指向封裝 ObjectA 等信息的 CacheObject 對象。然后,這個對象將被移動到 accessed LinkedList 的前面,還有其他一些動作如緩存清理、刪除、過期失效等都是在這個動作中一起觸發實現的。

    public class Cache implements Cacheable {

    ??? /**

    ???? * 因為 System.currentTimeMillis() 執行非常耗費性能,因此如果 get 操作都執行

    * 這條語句將會形成性能瓶頸, 通過一個全局時間戳來實現每秒更新

    * 當然,這意味著在緩存過期時間計算上有一到幾秒的誤差

    ???? */

    ??? protected static long currentTime = CacheTimer.currentTime;

    ??? //CacheObject 對象

    ??? protected HashMap cachedObjectsHash;

    ??? //accessed LinkedList 最經常訪問的排列在最前面

    ??? protected LinkedList lastAccessedList;

    ??? // 以緩存加入順序排列,最后加入排在最前面;越早加入的排在最后面

    ??? protected LinkedList ageList;

    ??? // 緩存最大限制 默認是 128k 可根據內存設定,越大性能越高

    ??? protected int maxSize =? 128 * 1024;

    ??? // 當前緩存的大小

    ??? protected int size = 0;

    ??? // 最大生命周期時間,默認是沒有

    ??? protected long maxLifetime = -1;

    ??? // 緩存的擊中率,用于評測緩存效率

    ??? protected long cacheHits, cacheMisses = 0L;

    ?

    ??? public Cache() {

    ??????? // 構造 HashMap. 默認 capacity 11

    ??????? // 如果實際大小超過 11 HashMap 將自動擴充,但是每次擴充都

    // 是性能開銷,因此期初要設置大一點

    ??????? cachedObjectsHash = new HashMap(103);

    ??????? lastAccessedList = new LinkedList();

    ??????? ageList = new LinkedList();

    ??? }

    ??? public Cache(int maxSize) {

    ??????? this();

    ??????? this.maxSize = maxSize;

    ??? }

    ? ??public Cache(long maxLifetime) {

    ??????? this();

    ??????? this.maxLifetime = maxLifetime;

    ??? }

    ??? public Cache(int maxSize, long maxLifetime) {

    ??????? this();

    ??????? this.maxSize = maxSize;

    ??????? this.maxLifetime = maxLifetime;

    ??? }

    ??? public int getSize() {??????? return size;??? }

    ??? public int getMaxSize() {??????? return maxSize;??? }

    ?

    ??? public void setMaxSize(int maxSize) {

    ??????? this.maxSize = maxSize;

    ??????? // 有可能緩存大小超過最大值,需要激活刪除清理動作

    ??????? cullCache();

    ??? }

    ??? public synchronized int getNumElements() {

    ??????? return cachedObjectsHash.size();

    ??? }

    ?

    ??? /**

    ???? * 增加一個 Cacheable 對象

    * 因為 HashMap 不是線程安全的,所以操作方法要使用同步

    * 如果使用 Hashtable 就不必同步

    ???? */

    ??? public synchronized void add(Object key, Cacheable object) {

    ??????? // 刪除已經存在的 key

    ??????? remove(key);

    ??????? int objectSize = object.getSize();

    ??????? // 如果被緩存對象的大小超過最大值,就放棄

    ??????? if (objectSize > maxSize * .90) {??????????? return;??????? }

    ??????? size += objectSize;

    ??????? // 創建一個 CacheObject 對象

    ??????? CacheObject cacheObject = new CacheObject(object, objectSize);

    ??????? cachedObjectsHash.put(key, cacheObject);? // 保存這個 CacheObject

    ??????? // 加入 accessed LinkedList Jive 自己的 LinkedList 在加入時可以返回值

    ??????? LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);

    ??????? // 保存引用

    ??????? cacheObject.lastAccessedListNode = lastAccessedNode;

    ??????? // 加入到 age LinkedList

    ??????? LinkedListNode ageNode = ageList.addFirst(key);

    ??????? // 這里直接調用 System.currentTimeMillis(); 用法值得討論

    ??????? ageNode.timestamp = System.currentTimeMillis();

    ??????? // 保存引用

    ??????? cacheObject.ageListNode = ageNode;

    ??????? // 做一些清理工作

    ??????? cullCache();

    ??? }

    ??? /**

    ???? * 從緩存中獲得一個被緩存的對象,這個方法在下面兩種情況返回空

    ???? *??? <li> 該對象引用從來沒有被加入緩存中

    ???? *??? <li> 對象引用因為過期被清除 </ul>

    ???? */

    ??? public synchronized Cacheable get(Object key) {

    ??????? // 清除過期緩存

    ??????? deleteExpiredEntries();

    ??????? // Key 從緩存中獲取一個對象引用

    ??????? CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);

    ??????? if (cacheObject == null) {

    ??????????? // 不存在,增加未命中率

    ??????????? cacheMisses++;

    ??????????? return null;

    ??????? }

    ??????? // 存在,增加命中率

    ??????? cacheHits++;

    ??????? // accessed LinkedList 中將對象從當前位置刪除

    ??????? // 重新插入在第一個

    ??????? cacheObject.lastAccessedListNode.remove();

    ??? ????lastAccessedList.addFirst(cacheObject.lastAccessedListNode);

    ??????? return cacheObject.object;

    ??? }

    ??? …

    }

    Cache 中,關鍵字 Key 是一個對象,為了再次提高性能,可以進一步將 Key 確定為一個 long 類型的整數。

    4.2? 緩存使用

    建立 LongCache 只是為了提高原來的 Cache 性能,本身無多大意義,可以將 LongCache 看成與 Cache 一樣的類。

    LongCache 的關鍵字 Key Forum ForumThread 以及 ForumMessage long 類型的 ID ,值 Value Forum ForumThread 以及 ForumMessage 等的對象。這些基本是通過 DatabaseCacheManager 實現完成,在主要類 DbForumFactory 的初始化構造時,同時構造了 DatabaseCacheManager 的實例 cacheManager

    前面過濾器功能分析中, Message 對象獲得方法的第一句如下:

    protected ForumMessage getMessage(long messageID, long threadID, long forumID) throws

    ????? ForumMessageNotFoundException {

    ??? DbForumMessage message = cacheManager.messageCache.get(messageID);

    ??? …

    }

    其中, cacheManager DatabaseCacheManager 的實例, DatabaseCacheManager 是一個緩存 Facade 類。在其中包含了 5 種類型的緩存,都是針對 Jive 5 個主要對象, DatabaseCacheManager 主要代碼如下:

    public class DatabaseCacheManager {

    ?? ?public UserCache userCache;??????? ????????????????? // 用戶資料緩存

    ??? public GroupCache groupCache;?????? ??????????????? // 組資料緩存

    ??? public ForumCache forumCache;????? ???????????????? //Forum 論壇緩存

    ??? public ForumThreadCache threadCache; ?????????????? //Thread 主題緩存

    ??? public ForumMessageCache messageCache;????????? //Message 緩存

    ??? public UserPermissionsCache userPermsCache;???? // 用戶權限緩存

    ?

    ??? public DatabaseCacheManager(DbForumFactory factory) {

    ??????? …

    ??????? forumCache =

    ??????????? new ForumCache(new LongCache(forumCacheSize, 6*HOUR), factory);

    ??????? threadCache =

    ??????????? new ForumThreadCache(

    ????????????????? new LongCache(threadCacheSize, 6*HOUR), factory);

    ??????? messageCache = new ForumMessageCache(

    ????????????????? new LongCache(messageCacheSize, 6*HOUR), factory);

    ??????? userCache = new UserCache(

    ????????????????? new LongCache(userCacheSize, 6*HOUR), factory);

    ??????? groupCache = new GroupCache(

    ????????????????? new LongCache(groupCacheSize, 6*HOUR), factory);

    ??????? userPermsCache = new UserPermissionsCache(

    ??????????????? new UserPermsCache(userPermCacheSize, 24*HOUR), factory

    ??????? );

    ??? }

    ??? …

    }

    從以上代碼看出, ForumCache 等對象生成都是以 LongCache 為基礎構建的,以 ForumCache 為例,代碼如下:

    public class ForumCache extends DatabaseCache {

    ??? // Cache 構建 ID 緩存

    ??? protected Cache forumIDCache = new Cache(128*1024, 6*JiveGlobals.HOUR);

    ??? // LongCache 構建整個對象緩存

    ??? public ForumCache(LongCache cache, DbForumFactory forumFactory) {

    ??????? super(cache, forumFactory);

    ??? }

    ?

    ??? public DbForum get(long forumID) throws ForumNotFoundException {

    ??????? …

    ??????? DbForum forum = (DbForum)cache.get(forumID);

    ??????? if (forum == null) {??? // 如果緩存沒有從數據庫中獲取

    ??????????? forum = new DbForum(forumID, factory);

    ??????????? cache.add(forumID, forum);

    ??????? }

    ??????? return forum;

    ??? }

    ?

    public Forum get(String name) throws ForumNotFoundException {

    ?????? ??// name key ,從 forumIDCache 中獲取 ID

    ?CacheableLong forumIDLong = (CacheableLong)forumIDCache.get(name);

    ??????? if (forumIDLong == null) { // 如果緩存沒有 從數據庫獲得

    ??????????? long forumID = factory.getForumID(name);

    ??????????? forumIDLong = new CacheableLong(forumID); // 生成一個緩存對象

    ??????????? forumIDCache.add(name, forumIDLong);

    ??????? }

    ??????? return get(forumIDLong.getLong());

    ??? }

    ??? …

    }

    由此可以看到, LongCache 封裝了 Cache 的核心功能,而 ForumCache 等類則是在 LongCache 核心外又包裝了與應用系統相關的操作,這有點類似裝飾( Decorator )模式。

    從中也可以看到 Cache LongCache 兩種緩存的用法。

    使用 Cache 時的關鍵字 Key 是任何字段。如上面代碼中的 String name ,如果用戶大量帖子主題查詢中, Key query + blockID ,見 DbForum 中的 getThreadBlock 方法;而值 Value 則是 Long 類型的 ID ,如 ForumID ThreadID 等。

    LongCache 的關鍵字 Key Long 類型的 ID ,如 ForumID ThreadID 等;而值 Value 則是 Forum ForumThread ForumMessage 等主要具體對象。

    在實際使用中,大多數是根據 ID 獲得對象。但有時并不是這樣,因此根據應用區分了兩種 Cache ,這其實類似數據庫的數據表,除了主關鍵字外還有其他關鍵字。

    4.3? 小結

    緩存中對象是原對象的映射,如何確保緩存中對象和原對象的一致性?即當原對象發生變化時,緩存中的對象也必須立即更新。這是緩存機制需要解決的另外一個基本技術問題。

    Jive 中是在原對象發生變化時,立即進行清除緩存中對象,如 ForumMessage 對象的創建。在 DbForumThread AddMessage 方法中有下列語句:

    factory.cacheManager.threadCache.remove(this.id);

    factory.cacheManager.forumCache.remove(this.forumID);

    即當有新的帖子加入時,將 ForumThreadCache ForumCache 相關緩沖全部清除。這樣,當有相關對象讀取時,將直接從數據庫中讀取,這是一種非常簡單的緩存更新方式。

    在復雜的系統,例如有一臺以上的服務器運行著 Jive 系統。如果一個用戶登陸一臺服務器后,通過這臺服務器增加新帖。那么按照上述原理,只能更新本服務器 JVM 中的緩存數據,而其他服務器則無從得知這種改變,這就需要一種分布式的緩存機制。

    3-7? Jive 主要對象的訪問

    到目前可以發現 整個 Jive 系統其實是圍繞 Forum ForumThread ForumMessage 等這些主要對象展開的讀取、修改或創建等操作。由于這些對象原先持久化保存在數據庫中,為了提高性能和加強安全性, Jive 在這些對象外面分別實現兩層包裝,如圖 3-7 所示。

    客戶端如果需要訪問這些對象,首先要經過它們的代理對象。進行訪問權限的檢查,然后再從緩存中獲取該對象。只有緩存不存在時,才會從數據庫中獲取。

    這套機制是大多數應用系統都面臨的必須解決的基本功能,因此完全可以做成一個通用的可重復使用的框架。這樣在具體應用時,不必每個應用系統都架設開發這樣的機制。其實 EJB 就是這樣一套框架,實體 Bean 都由緩存機制支持,而通過設定 ejb-jar.xml 可以實現訪問權限控制,這些工作都直接由 EJB 容器實現了,不必在代碼中自己來實現。剩余的工作是調整 EJB 容器的參數,使之適合應用系統的具體要求,這些將在以后章節中討論。

    Jive 中,圖 3-7 的機制是通過不同方式實現的。基本上是一配二模式:一個對象有一個緩沖對象和一個代理對象,這樣做的一個缺點是導致對象太多,系統變得復雜。這點在閱讀 Jive 源碼時可能已經發現。

    如果建立一個對象工廠,工廠內部封裝了圖 3-7 機制實現過程,客戶端可以根據不同的工廠輸入參數獲得具體不同的對象。這樣也許代碼結構要更加抽象和緊湊, Java 的動態代理 API 也許是實現這個工廠的主要技術基礎。有興趣者可以進一步研究提煉。

    posted on 2006-08-31 12:27 Alex 閱讀(442) 評論(0)  編輯  收藏 所屬分類: java
    主站蜘蛛池模板: 91热久久免费精品99| 久久免费观看国产精品88av| 成人免费观看男女羞羞视频| 99re6在线精品免费观看| 69视频在线观看高清免费| 成人午夜免费福利| 亚洲精品视频免费| 亚洲免费视频网站| 色天使亚洲综合在线观看| 免费无码又爽又黄又刺激网站| a视频在线观看免费| 波多野结衣在线免费视频| 国产精品免费小视频| 国产亚洲av片在线观看16女人| 亚洲伊人色一综合网| 看全免费的一级毛片| 久久成人无码国产免费播放| 成年人视频在线观看免费| 亚洲国产成人久久一区WWW| 亚洲A∨无码一区二区三区| 亚洲一本到无码av中文字幕| 男女一边桶一边摸一边脱视频免费| 3d动漫精品啪啪一区二区免费| 日本午夜免费福利视频| 亚洲国产AV无码专区亚洲AV| 亚洲va在线va天堂成人| 国产一级a毛一级a看免费人娇| 日韩精品福利片午夜免费观着| 国产gv天堂亚洲国产gv刚刚碰| 亚洲国产情侣一区二区三区| 天堂亚洲免费视频| 在线看片v免费观看视频777| 国产精品亚洲产品一区二区三区| 亚洲国产精品久久人人爱| 亚洲一区二区三区免费| 成视频年人黄网站免费视频| 中文字幕精品亚洲无线码二区| 中文字幕乱码亚洲精品一区| 中文字幕无码免费久久| 在线视频免费国产成人| 亚洲理论片中文字幕电影|