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

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

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

    Kevin.Zhong

    彪悍的人生不需要解釋,彪悍的代碼不需要測試。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      17 隨筆 :: 12 文章 :: 14 評論 :: 0 Trackbacks

    Cache Insight

    前言
    首先,介紹一下我(作者)自己使用Cache的背景,以便讀者更清楚地了解我下面要講述哪些內容。
    我主要是一個Cache實現者,而不是使用者。為了給一些ORM(比如JPA實現)提供Cache支持,我需要包裝其它的Open Source Cache,并考察它們的特性。
    我對這些Open Source Cache的一些工作原理,了解得比較多。具體配置和使用細節,了解的比較少。
    本文主要講述的也是Cache的特性和工作原理,而不是一個安裝、配置、使用的入門手冊。
    本文簡述Cache的一般特性,詳述Cache的高級特性,比如,分布式Cache,關聯對象的Cache,POJO Cache等。
    閱讀本文需要具備基本的Cluster知識,ORM知識,數據庫事務知識。本文不解釋這些基本概念。

    -------------------------------------------------------
    Cache Features
    首先,我們來瀏覽一下常見的Cache。
    這個鏈接給出了常用的Java Open Source Cache。
    http://java-source.net/open-source/cache-solutions

    memcached,JBoss Cache,SwarmCache,OSCache,JCS,EHCache等開源項目的出鏡率和關注率比較高。
    memcached和其他幾個不同,后面會詳述。
    JBoss Cache的特點是,功能大而全,可算是Cache集大成者,幾乎什么都支持。
    其余的幾個都很輕量。SwarmCache,OSCache,JCS支持Cluster。EHCache不支持Cluster。

    下面列出Cache的基本特性。
    1. 時間記錄
    數據進入Cache的時間。

    2. timeout過期時間
    Cache里面的數據多久過期

    3. Eviction Policy 清除策略
    Cache滿了之后,根據什么策略,應該清除哪些數據。
    比如,最不經常被訪問的數據,最久沒有訪問到的數據。

    4. 命中率
    Cache的數據被選中的比率

    5. 分級Cache
    有些Cache有分級的概念。比如,幾乎所有的Cache都支持Region分區的概念。可以指定某一類的數據存放在特定的Region里面。JBoss Cache可以支持更多的級別。

    6. 分布式Cache
    分布在不同計算機上的Cache

    7. 鎖,事務,數據同步
    一些Cache提供了完善的鎖,事務支持。

    以上特性,大部分Cache都有相應的API支持。這些API很直觀,也很簡單,本文不打算展開講述。
    本文下面主要介紹,memcached和JBoss Cache這兩個具有代表意義的Cache的高級特性,包括分布式Cache的支持。

    -------------------------------------------------------

    memcached
    http://www.danga.com/memcached/

    memcached是一個Client Server結構的遠程Cache實現。
    Server是用C寫的,提供了多種語言的客戶端API,包括Java, C#, Ruby, Python, PHP, Perl, C等多種語言。
    memcached主要使用在Shared Nothing Architecture中。應用程序通過客戶端API,從memcached server存取數據。
    典型的應用,比如,用memcached作為數據庫緩存。
    也常有這樣的用法,用memcached存放HTTP Session的數據。具體做法是包裝Session Interface,截獲setAttribute(), getAttribute()方法。

    MemcachedSessionWrapper {
      Object getAttribute( key ){
        return memcachedClient.get (session.getId() + key);
      }
      void setAttribute( key, value ){
        memcachedClient.setObject(session.getId() + key, value);
      }
    }

    不同計算機上的應用程序通過一個IP地址來訪問memcahced Server。
    同一個key對應的數據,只存在于一臺memcached server的一份內存中。
    memcached server也可以部署在多臺計算機上。Memcached通過key的hashcode來判斷從哪臺memcached server上存取數據數據。我們可以看到,同一個key對應的數據,還是只存在于一臺memcached server的一份內存中。
    所以,memcached不存在數據同步的問題。這個特性很關鍵,我們后面講到Cluster Cache的時候,就會涉及到數據同步的問題。
    memcached由于是遠程Cache,要求放到Cache的Key和Value都是Serializable。
    遠程Cache,最令人擔心的網絡通信開銷。據有經驗的人說,memcached網絡通信開銷很小。
    memcached的API設計也是遠程通信友好的,提供了getMulti()等高粒度的調用方法,能夠批量獲取數據,從而減少網絡通信次數。

    -------------------------------------------------------

    JBoss Cache
    http://www.jboss.org/products/jbosscache

    有一個商業Cluster Cache,叫做tangosol。
    JBoss Cache是我唯一知道的能夠和tangosol媲美的開源Cache。

    Cluster Cache的數據同步,需要網絡通信,這就要求放到Cache的數據是Serializable。
    JBoss Cache提出了POJO Cache的概念,意思是數據不是Serializable,一樣能夠在Cluster中同步。
    JBoss POJO Cache通過AOP機制,支持對象同步,支持對象屬性的同步,支持關聯對象的Cache,支持繼承,集合,Query,并支持不同級別的事務,儼然一個小型內存數據庫級別的數據存儲系統。
    下面進行解釋。
    最令人迷惑不解的是這個POJO的Cluster同步如何實現。
    JBoss POJO Cache采用AOP來照管了POJO的通信和傳播工作。天下沒有免費的午餐,POJO不支持序列化,框架本身就要做這個工作——Marshal and Unmarshal,比如通過把Java對象翻譯成XML,傳播出去,對方收到XML,再翻譯成Java對象。
    上面說了,JBoss POJO Cache很像一個小型存儲容器,JBoss POJO Cache的對象管理也非常類似Hibernate,JDO,JPA等ORM工具,同樣有Detach和Attach的概念。
    Attach就是put,把對象放入到Cache中。Detach就是remove,把對象從Cache中刪除。為啥要多起個名?
    原因是,put的時候,放進去的是個干干凈凈的POJO,出來的時候,就是Enhanced Object,里面夾雜了很多Interceptor代碼,監聽對象的方法。
    你操作這個對象的時候,JBoss AOP框架就獲得了相應的通知,能夠做出相應的反應,比如數據同步等。
    JBoss POJO Cache支持對集合類型的AOP。同樣需要把集合Attach(Put)進Cache,然后get出來,然后對集合進行操作,就可以被JBoss AOP截獲了。

    JBoss POJO Cache的基礎是JBoss Tree Cache。這個Tree Cache類似于一個XML DOM樹形數據結構。
    JBoss Cache采用Full Qualified Name作為Cache Key,類似于XPath。比如,a/b/c/d。
    當你刪除a/b的時候,a/b/c,a/b/c/d等所有屬于a/b的Key和對應數據,都被刪除。
    JBoss Cache的findObjects方法能夠找出一串對象。比如,findObjects根據a/b/c/d能夠找出a,b,c,d等4個對象,放在一個Map中返回。
    具體用法要參見API詳細說明,因為JBoss POJO Cache提供了很多行為模式。
    這種分級的Cache功能很有用,實現起來也不難。只是,我覺得,還是不夠強大。既然支持了類似于XPath的Key,不如索性支持XPath的 條件查詢。比如,a[name=”n”]/b/c。當然,實現這種功能的代價非常大,需要遍歷整個Cache Tree,正如XPath需要遍歷整個DOM節點一樣。

    最后,JBoss Cache和tangosol一樣,都支持了一個我認為如同雞肋一般的功能,鎖機制和事務支持。這個事務支持的意思是,Cache本身實現了類似于數據庫的4種事務隔離級別。
    在我看來,這種支持無疑是為了賺取眼球。Cache不當做Cache來用,搞些歪門邪道,大而不當。想當作數據庫來用,那還不如把主要功夫花在上述提到的那種精確批量查詢功能上。

    -------------------------------------------------------
    Cluster同步

    Cluster之間的Cache同步有多種實現方法。比如,JMS,RMI,Client Server Socket等方法,用的最多的,支持最廣的方法是JGroups開源項目實現的Multicast。配置Cluster Cache,通常就相當于配置JGroups,需要閱讀JGroups配置文檔。
    Cache的操作通常有4個,get,put,remove,clear。
    對于Cluster Cache來說,讀操作(get)肯定是Local方法,只需要從本臺計算機內存中獲取數據。Remove/clear兩個寫操作,肯定是Remote方 法,需要和Cluster其他計算機進行同步。Put這個寫方法,可以是Local,也可以是Remote的。
    Remote Put方法的場景是這樣,一臺計算機把數據放到Cache里面,這個數據就會被傳播到Cluster其他計算機上。這個做法的好處是Cluster各臺計算機的Cache數據可以及時得到補充,壞處是傳播的數據量比較大,這個代價比較大
    Local Put方法的場景是這樣,一臺計算機把數據放到Cache里面,這個數據不會被傳播到Cluster其他計算機上。這個做法的好處是不需要傳播數據,壞處 是Cluster各臺計算機的Cache數據不能及時得到補充,這個不是很明顯的問題,從Cache中得不到數據,從數據庫獲取數據是很正常的現象。
    Local Put比起Remote Put的優勢很明顯,所以,通常的Cluster Cache都采用Local Put的策略。各Cache一般都提供了Local Put的配置選項,如果你沒有看到這個支持,那么請換一個Cache。:D

    -------------------------------------------------------

    Center vs Cluster
    Memcached可以看作是Center Cache。
    Center Cache和Cluster Cache的特性比較如下:
    Center Cache沒有同步問題,所以,remove/clear的時候,比較有優勢,不需要把通知發送到好幾個計算機上。
    但是,Center Cache的所有操作,get/put/remove/clear都是Remote操作。而Cluster Cache的get/put都是Local操作,所以,Cluster Cache在get/put操作上具有優勢。

    Local get/put在關聯對象的組裝和分拆方面,優勢比較明顯。
    關聯對象的分拆是這個意思。
    比如,有一個Topic對象,下面有幾個Post對象,每個Post對象都有一個User對象。
    Topic對象存放到Cache中的時候,下面的關聯對象都要拆開來,分成各自的Entity Region來存放。
    Topic Region -> Topic ID -> Topic Object
    Post Region -> Post ID -> Post Object
    User Region -> User ID -> User Object
    這個時候,put的動作可能發生多次。Remote Put的開銷就比較大。
    Get的過程類似,也需要get多次,才能拼裝成一個完整的Topic對象。


    -------------------------------------------------------

    過期數據
    Cache可以用在任何地方,比如,頁面緩存。但Cache的最常用場景是用在ORM中,比如,Hibernate,JDO,JPA中。
    ORM Cache的使用方法有個原則——不要把沒有Commit的修改數據放入到緩存中。這是為了防止Read Dirty。
    數據庫事務分為兩種,一種是讀事務,不修改數據,一種是寫事務,修改數據。
    寫事務的操作流程如下:
    db.commt();
    cache.remove(key); // 這一步操作,清除了Cache數據,也記錄了一個時間removeTime。

    讀事務的操作流程如下:
    readTime = current time;
    data = cache.get(key);
    if(data is null){
      data = db.load(key);
      cache.put(key, data, readTime); // 這里要readTime傳進去
    }

    這里需要注意的是put的時候,需要readTime這個參數。
    這個readTime要和上一次的removeTime進行比較。
    如果readTime > removeTime,這個put才能成功,數據才能夠進入緩存。
    這是為了保證不把過期數據放入到Cache中,及時反映數據庫的變化。

    另外,需要注意的是,cache.remove(key); 這個事件需要傳播到Cluster其他計算機,通知它們清理緩存。
    為什么需要這個通知?
    一定要注意,這不是為了避免并發修改沖突。并發修改沖突的避免需要引入樂觀鎖版本控制機制。
    有可能存在這樣的誤解,認為有了樂觀鎖版本控制機制,就不需要Cache.remove通知了。這是不對的。
    Cache.remove通知的主要目的是,保證緩存能夠及時清理過期數據,反映數據的變化,保證大部分時間內,應用程序顯示給用戶的不是過期數據。
    另外,db.commt(); cache.remove(key); 這兩步調用之間,有很小的可能發生另外的事務。這段極小的時間內,可能無法保證Read Committed,可能出現很短期的過期數據。
    為什么說很短期,因為緊接著的Cache.remove就會清理過期數據。
    如果偏執到這種程度,這么短期的幾乎不可能發生的小概率事件,都不能容忍,那么可以,db.commt()之前,給Cache加一個悲觀鎖,不讓別的事務,把數據Put進入Cache,就可以防止這個小概率、微影響的事件。
    JBoss Cache和Tangosol就提供了這類雞肋一般的悲觀鎖機制。典型的開發資源配置不當,有用的需要的不做,沒用的功能使勁做。
    ORM Query Cache
    ORM Cache一般分為兩種。一種是ID Cache(ORM文檔中稱為二級Cache),用來存放Entity ID對應的Entity對象;一種是Query Cache,用來存放一條查詢語句對應的查詢結果集。
    ID Cache非常直觀,如同上述講述的,一般是一個Entity Class對應一個Region,Entity存放到對應的Region里面。
    Query Cache比較復雜,而且潛在作用很大,值得仔細講解。
    現有的ORM對Query Cache的支持并不是很理想。
    比如,Hibernate把整個結果集直接放在Query Cache中。這樣,有任何風吹草動,發生了任何數據庫的寫操作,Query Cache都需要清空。
    有一種比較好的做法,把ID List存放在Query Cache中,每次獲取的時候,先獲取ID List,然后根據ID List獲取Entity List。Query Cache根據Query涉及到的Table Name來進行清理,一旦發生對這些Table Name的修改操作,就可以根據不同情況,清理Query Cache。
    比如,select t2.* from t1, t2 where t1.id = t2.foreign_id and t1.name = ‘a’
    那么insert into t1, delete from t1, insert into t2, delete from t2都會清除這條Query Cache。
    同樣的 update t1 set name = … 這樣的語句也會清除這條Query Cache。
    Hibernate為什么不這么做,因為Query Cache的情況比較復雜。也許選擇的結果集并不是只有一個Entity類型,也許只是幾個字段。
    這個地方,如果細分,還是有很多功夫可以做的。而且也很值得花功夫做,因為Query Cache對于性能的提高,有很大作用。

    -------------------------------------------------------

    ORM Query Cache
    Cache可以用在任何地方,比如,頁面緩存。但Cache的最常用場景是用在ORM中,比如,Hibernate,JDO,JPA中。
    ORM Cache一般分為兩種。一種是ID Cache(ORM文檔中稱為二級Cache),用來存放Entity ID對應的Entity對象;一種是Query Cache,用來存放一條查詢語句對應的查詢結果集。
    ID Cache非常直觀,如同上述講述的,一般是一個Entity Class對應一個Region,Entity存放到對應的Region里面。
    Query Cache比較復雜,而且潛在作用很大,值得仔細講解。
    現有的ORM對Query Cache的支持并不是很理想。
    比如,Hibernate把整個結果集直接放在Query Cache中。這樣,有任何風吹草動,發生了任何數據庫的寫操作,Query Cache都需要清空。
    有一種比較好的做法,把ID List存放在Query Cache中,每次獲取的時候,先獲取ID List,然后根據ID List獲取Entity List。Query Cache根據Query涉及到的Table Name來進行清理,一旦發生對這些Table Name的修改操作,就可以根據不同情況,清理Query Cache。
    比如,select t2.* from t1, t2 where t1.id = t2.foreign_id and t1.name = ‘a’
    那么insert into t1, delete from t1, insert into t2, delete from t2都會清除這條Query Cache。
    同樣的 update t1 set name = … 這樣的語句也會清除這條Query Cache。
    Hibernate為什么不這么做,因為Query Cache的情況比較復雜。也許選擇的結果集并不是只有一個Entity類型,也許只是幾個字段。
    這個地方,如果細分,還是有很多功夫可以做的。而且也很值得花功夫做,因為Query Cache對于性能的提高,有很大作用。

    -----------------------------------------------------------

    Query Key
    Query Cache的性能需要考慮幾個方面。比如,Query Key。Query Key一般由2個部分組成:Query String部分,SQL, HQL, EQL, or OQL;參數部分。
    尋找Query Key的對應數據的時候,Query Key的比較有兩個步驟,先hash,然后equals。所以,Query Key的hashcode和equals兩個方法很重要。尤其是equals方法。
    equals方法需要比較很長的Query String。如果沒有命中,Query String不相等,那么開銷很小,因為通常來說,不相等的String長度都不同,或者前面的字符串都不相同。開銷最大的是命中的時候,Query String相等,那么需要把String從頭比到尾。
    我們可以采取一些方法來提高String的比較速度。比如,大部分的情況屬于靜態查詢,我們可以采用Singleton String。相同reference的String之間的比較速度很快。對于ORM來說,最好直接使用最外面的HQL, EQL, OQL作為Query Key,而不是采用生成的SQL結果。因為生成的SQL結果每次都是一個新String,具有不同的reference,Cache命中的時候,需要比較 整個字符串。
    動態拼裝的Query String的性能提高比較難辦。因為最終的結果,都是一個新String。我采用的一種方式是,動態拼裝的結果是一個String[]。兩個 String[]如果相等,那么里面的元素String的reference都是相等的,這是由JVM對一個Class內部的String常量進行優化的 結果。
    比如,
    String[] a = {
      “select * from t where”
      “a = 1”
      “and b = 2”
    };

    String[] b = {
      “select * from t where”
      “a = 1”
      “and b = 2”
    };

    那么a和b的比較只需要3次String reference的比較。
    posted on 2008-10-15 11:49 Kevin.Zhong 閱讀(350) 評論(0)  編輯  收藏 所屬分類: memcache
    主站蜘蛛池模板: 国内精品久久久久影院免费| 特级无码毛片免费视频| 无码av免费一区二区三区试看| 国产亚洲精品高清在线| 高清免费久久午夜精品| 亚洲成人一区二区| 一边摸一边爽一边叫床免费视频| 婷婷亚洲天堂影院| 一级毛片在线播放免费| 亚洲伊人成无码综合网| 巨胸狂喷奶水视频www网站免费| 久久精品国产亚洲Aⅴ香蕉| 中文字幕无码毛片免费看| 亚洲欧洲日韩国产综合在线二区| 日韩免费电影网站| 亚洲成aⅴ人片在线观| 成人免费一区二区三区在线观看| 亚洲国产欧美国产综合一区 | 亚洲国产区男人本色在线观看| 久久精品无码一区二区三区免费 | 亚洲AV无码久久精品蜜桃| 无码人妻AV免费一区二区三区| 亚洲最大视频网站| 日本视频免费在线| 黄色网站软件app在线观看免费| 久久亚洲精品无码AV红樱桃| 无码国产精品一区二区免费虚拟VR | 亚洲精品午夜在线观看| 德国女人一级毛片免费| 一区二区三区视频免费观看| 亚洲2022国产成人精品无码区| 91成人免费在线视频| 未满十八私人高清免费影院| 亚洲国产精品一区| 色www永久免费视频| 中国一级特黄的片子免费| 亚洲另类图片另类电影| 亚洲不卡无码av中文字幕| 免费不卡在线观看AV| 激情小说亚洲图片| 亚洲国产综合在线|