1. 程式人生 > >叢集環境中使用 EhCache 快取系統

叢集環境中使用 EhCache 快取系統

EhCache 快取系統簡介:
   EhCache 是一個純 Java 的程序內快取框架,具有快速、精幹等特點,是 Hibernate 中預設的 CacheProvider。
 下圖是 EhCache 在應用程式中的位置:

 EhCache 的主要特性有:

1.快速;

2.簡單;

3.多種快取策略;

4.快取資料有兩級:記憶體和磁碟,因此無需擔心容量問題;

5.快取資料會在虛擬機器重啟的過程中寫入磁碟;

6.可以通過 RMI、可插入 API 等方式進行分散式快取;

7.具有快取和快取管理器的偵聽介面;

8.支援多快取管理器例項,以及一個例項的多個快取區域;

9.提供 Hibernate 的快取實現;

10.等等 …   

     由於 EhCache 是程序中的快取系統,一旦將應用部署在叢集環境中,每一個節點維護各自的快取資料,當某節點對快取資料進行更新,這些更新的資料無法在其它節點中共享,這不僅會降低節點執行的效率,而且會導致資料不同步的情況發生。例如某個網站採用 A、B 兩個節點作為叢集部署,當 A 節點的快取更新後,而 B 節點快取尚未更新就可能出現使用者在瀏覽頁面的時候,一會是更新後的資料,一會是尚未更新的資料,儘管我們也可以通過 Session Sticky 技術來將使用者鎖定在某個節點上,但對於一些互動性比較強或者是非 Web 方式的系統來說,Session Sticky 顯然不太適合。所以就需要用到 EhCache 的叢集解決方案。

EhCache 從 1.7 版本開始,支援五種叢集方案,分別是:
   • Terracotta
   • RMI
   • JMS
   • JGroups
   • EhCache Server
   

   本文主要介紹其中的三種最為常用叢集方式,分別是 RMI、JGroups 以及 EhCache Server 。

   RMI 叢集模式:
      RMI 是 Java 的一種遠端方法呼叫技術,是一種點對點的基於 Java 物件的通訊方式。EhCache 從 1.2 版本開始就支援 RMI 方式的快取叢集。在叢集環境中 EhCache 所有快取物件的鍵和值都必須是可序列化的,也就是必須實現 java.io.Serializable 介面,這點在其它叢集方式下也是需要遵守的。
下圖是 RMI 叢集模式的結構圖:

      圖 2. RMI 叢集模式結構圖:

      採用 RMI 叢集模式時,叢集中的每個節點都是對等關係,並不存在主節點或者從節點的概念,因此節點間必須有一個機制能夠互相認識對方,必須知道其它節點的資訊,包括主機地址、埠號等。EhCache 提供兩種節點的發現方式:手工配置和自動發現。手工配置方式要求在每個節點中配置其它所有節點的連線資訊,一旦叢集中的節點發生變化時,需要對快取進行重新配置。
由於 RMI 是 Java 中內建支援的技術,因此使用 RMI 叢集模式時,無需引入其它的 Jar 包,EhCache 本身就帶有支援 RMI 叢集的功能。使用 RMI 叢集模式需要在 ehcache.xml 配置檔案中定義cacheManagerPeerProviderFactory 節點。假設叢集中有兩個節點,分別對應的 RMI 繫結資訊是:
    

    自動方式:
      自動發現方式使用tcp廣播來建立和包含一個廣播組,它的特徵是最小配置和對成員組的自動新增和管理。沒有那個伺服器是有優先順序的。對等點每一秒中向廣播組傳送心跳,如果一個對等點在五秒鐘內沒傳送過來,則此對等點將會被刪除,如果有新的,則會被加入叢集。 

<span style="font-family:SimHei;font-size:18px;"> <cacheManagerPeerProviderFactory
 class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"   properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,  multicastGroupPort=1000, timeToLive=32" />
</span>
   解析:
      peerDiscovery 方式:atutomatic 為自動 ;mulicastGroupAddress 廣播組地址:230.0.0.1;mulicastGroupPort 廣播組埠:40001;timeToLive 搜尋某個網段上的快取:0是限制在同一個伺服器,1是限制在同一個子網,32是限制在同一個網站,64是限制在同一個region,128是同一塊大陸,還有個256,我就不說了;hostName:主機名或者ip,用來接受或者傳送資訊的介面。同時組播地址可以指定 D 類 IP 地址空間,範圍從 224.0.1.0 到 238.255.255.255 中的任何一個地址。

    如下是詳細的配置:

     Server1- 1000:   

<span style="font-family:SimHei;font-size:18px;">    <cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,
            multicastGroupPort=1000, timeToLive=32" />
<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />
<!-- 預設快取 -->
    <defaultCache maxElementsInMemory="1000" eternal="true"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
    </defaultCache>
    
    <!-- demo快取 -->
    <cache name="user" maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
        <!-- 用於在初始化快取,以及自動設定 -->
        <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
    </cache>
</span>
    
 Server2 -2000:       

<span style="font-family:SimHei;font-size:18px;"><cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1,
            multicastGroupPort=1000, timeToLive=32" />
<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />
           
     <!-- 預設快取 -->
     <defaultCache maxElementsInMemory="1000" eternal="true"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
     </defaultCache>
    
    
    <!-- demo快取 -->
    <cache name="user" maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
        <!-- 用於在初始化快取,以及自動設定 -->
        <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
    </cache>
</span>
  手動配置:
    手動成員發現需要給監聽器配置ip地址和埠。任何成員不能在執行的時候新增和移除。手動的成員發現推薦在組播不能實現的時候使用,比如叢集的路由不允許傳送組播報文的時候。你也可以單向的快取資料同步,比如讓server2可以同步server1的資料,但sever1不能同步server2的。
配置手動發現成員時需要配置cacheManagerPeerProviderFactory的如下屬性
      peerDiscovery=manual
      rmiUrls=//server:port/cacheName, ...
      rmiUrls是快取成員的列表,但是不包括自己,也就是被配置的這臺伺服器的地址。

   案例:

     比如你的叢集裡有server1和server2兩臺伺服器,你希望同步 user
     下面是server1-2000的配置:   

<span style="font-family:SimHei;font-size:18px;"><cacheManagerPeerProviderFactory 
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
            properties="hostName=127.0.0.1,
            port=2000,
            socketTimeoutMillis=12000,
            peerDiscovery=manual,
            rmiUrls=//127.0.0.1:1000/user"
     /> 
 <cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName=127.0.0.1,port=2000,socketTimeoutMillis=120000" />
<!-- demo快取 -->
    <cache name="user" maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
        <!-- 用於在初始化快取,以及自動設定 -->
        <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
    </cache>
 
 
 如果想配置多個:rmiUrls=//127.0.0.1:1000/test1| rmiUrls=//127.0.0.1:1000/test2
 
下面是server2-1000的配置:
<cacheManagerPeerProviderFactory 
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=12000,
            peerDiscovery=manual, rmiUrls=//127.0.0.1:2000/user"
        />
<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
        properties="hostName=127.0.0.1,port=1000,socketTimeoutMillis=120000" />
<!-- demo快取 -->
    <cache name="user" maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
        <!-- 用於在初始化快取,以及自動設定 -->
        <bootstrapCacheLoaderFactory  class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
    </cache>
</span><span style="font-family: SimHei; font-size: 18px; background-color: rgb(255, 255, 255);">   </span>
 JGroups 叢集模式:
    Jgroups入門與實踐
                   

    EhCache 從 1.5. 版本開始增加了 JGroups 的分散式叢集模式。與 RMI 方式相比較, JGroups 提供了一個非常靈活的協議棧、可靠的單播和多播訊息傳輸,主要的缺點是配置複雜以及一些協議棧對第三方包的依賴。
JGroups 也提供了基於 TCP 的單播 ( Unicast ) 和基於 UDP 的多播 ( Multicast ) ,對應 RMI 的手工配置和自動發現。使用單播方式需要指定其它節點的主機地址和埠,下面是兩個節點.

    單播方式配置:                              
<span style="font-family:SimHei;font-size:18px;">  <cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
        properties="connect=TCP(bind_addr=127.0.0.1;bind_port=1000):
                            TCPPING(initial_hosts=127.0.0.1[1000],127.0.0.1[2000];port_range=1;timeout=5000;num_initial_members=2):
                            MERGE2(min_interval=3000;max_interval=5000):
                            FD_ALL(interval=5000;timeout=20000):
                            FD(timeout=5000;max_tries=48;):
                            VERIFY_SUSPECT(timeout=1500):
                            pbcast.NAKACK(retransmit_timeout=100,200,300,600,1200,2400,4800;discard_delivered_msgs=true):
                            pbcast.STABLE(stability_delay=1000;desired_avg_gossip=20000;max_bytes=0):
                            pbcast.GMS(print_local_addr=true;join_timeout=5000)"
        propertySeparator="::" /></span>
  使用多播方式配置如下:            
<span style="font-family:SimHei;font-size:18px;">             EhCache 的 Groups 叢集模式還有另外一種節點發現方式,
              就是通過多播( multicast )來維護叢集中的所有有效節點。
              這也是最為簡單而且靈活的方式,與手工模式不同的是,
              每個節點上的配置資訊都相同,大大方便了節點的部署,
              叢集啟動時會自動發現同一區域網的快取伺服器
              以jgroups 多播方式配置叢集,自動發現集節點
<cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
        properties="connect=UDP(mcast_addr=224.1.1.1;mcast_port=45678;ip_ttl=32;mcast_send_buf_size=120000;mcast_recv_buf_size=80000): 
        PING(timeout=2000;num_initial_members=2): 
        MERGE2(min_interval=5000;max_interval=10000): 
        FD_SOCK:VERIFY_SUSPECT(timeout=1500): 
        pbcast.NAKACK(retransmit_timeout=3000): 
        UNICAST(timeout=5000): 
        pbcast.STABLE(desired_avg_gossip=20000): 
        FRAG: 
        pbcast.GMS(join_timeout=5000;print_local_addr=true)"
        propertySeparator="::" />
</span>
   從上面的配置來看,JGroups 的配置要比 RMI 複雜得多,但也提供更多的微調引數,有助於提升快取資料複製的效能。詳細的 JGroups 配置引數的具體意義可參考 JGroups 的配置手冊。
   JGroups 方式對應快取節點的配置資訊如下:                  

<span style="font-family:SimHei;font-size:18px;"><!-- demo快取 
       replicateAsynchronously  物件同步是否非同步完成,預設為true。如果比較緊急就設為false。 在一致性時間性要求不強的時候,設為非同步可大大提供效能,因為它是非同步立即返回的,而且可以批量提交。 
       replicateUpdatesViaCopy 是否將物件變更復制到所有節點,還是隻是傳送一個失效資訊,讓對方該快取失效,當對方需要該快取時重新計算載入。 
預設為true。鑑於物件複製的消耗挺大的,又有鎖的問題,而且對方也未必需要該物件,所以此屬性建議設為false。如果業務上真的需要設為true時,就可考慮使用Terracotta了。 
       replicatePuts、replicateUpdates、replicateRemovals  增刪改是否同步,預設都為true。但因為我們前面選擇了失效演算法,所以replicatePuts 要設為false。 
    -->
    <cache name="user" maxElementsInMemory="1000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
        diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
        diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU">
        <cacheEventListenerFactory
            class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
            properties="replicateAsynchronously=true, replicatePuts=true,
        replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" />
        <!-- 用於在初始化快取,以及自動設定 -->
        <bootstrapCacheLoaderFactory
            class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory" />
    </cache>
</span>
   使用組播方式的注意事項:
    使用 JGroups 需要引入 JGroups 的 Jar 包以及 EhCache 對 JGroups 的封裝包 ehcache-jgroupsreplication-xxx.jar 。
在一些啟用了 IPv6 的電腦中,經常啟動的時候報如下錯誤資訊:
java.lang.RuntimeException: the type of the stack (IPv6) and the user supplied addresses (IPv4) don't match: /231.12.21.132.
解決的辦法是增加 JVM 引數:-Djava.net.preferIPv4Stack=true。如果是 Tomcat 伺服器,可在 catalina.bat 或者 catalina.sh 中增加如下環境變數即可:
    SET CATALINA_OPTS=-Djava.net.preferIPv4Stack=true

 EhCache Server:
    與前面介紹的兩種叢集方案不同的是, EhCache Server 是一個獨立的快取伺服器,其內部使用 EhCache 做為快取系統,可利用前面提到的兩種方式進行內部叢集。對外提供程式語言無關的基於 HTTP 的 RESTful 或者是 SOAP 的資料快取操作介面。
下面是 EhCache Server 提供的對快取資料進行操作的方法:

  OPTIONS /{cache}}

獲取某個快取的可用操作的資訊。

  HEAD /{cache}/{element}

獲取快取中某個元素的 HTTP 頭資訊,例如:

   curl --head  http://localhost:8080/ehcache/rest/sampleCache2/2

EhCache Server 返回的資訊如下:

HTTP/1.1 200 OK 

X-Powered-By: Servlet/2.5 

Server: GlassFish/v3 

Last-Modified: Sun, 27 Jul 2008 08:08:49 GMT 

ETag: "1217146129490"

Content-Type: text/plain; charset=iso-8859-1 

Content-Length: 157 

Date: Sun, 27 Jul 2008 08:17:09 GMT

  GET /{cache}/{element}

讀取快取中某個資料的值。

  PUT /{cache}/{element}

寫快取。

由於這些操作都是基於 HTTP 協議的,因此你可以在任何一種程式語言中使用它,例如 Perl、PHP 和 Ruby 等等。

下圖是 EhCache Server 在應用中的架構:

     圖 3. EhCache Server 應用架構圖:

    EhCache Server 同時也提供強大的安全機制、監控功能。在資料儲存方面,最大的 Ehcache 單例項在記憶體中可以快取 20GB。最大的磁碟可以快取 100GB。通過將節點整合在一起,這樣快取資料就可以跨越節點,以此獲得更大的容量。將快取 20GB 的 50 個節點整合在一起就是 1TB 了。

額外補充:
  ehcache.xml 屬性說明:
    屬性解釋:
    必須屬性:
        name:設定快取的名稱,用於標誌快取,惟一
        maxElementsInMemory:在記憶體中最大的物件數量
        maxElementsOnDisk:在DiskStore中的最大物件數量,如為0,則沒有限制
        eternal:設定元素是否永久的,如果為永久,則timeout忽略
        overflowToDisk:是否當memory中的數量達到限制後,儲存到Disk
    可選的屬性:
        timeToIdleSeconds:設定元素過期前的空閒時間
        timeToLiveSeconds:設定元素過期前的活動時間
        diskPersistent:是否disk store在虛擬機器啟動時持久化。預設為false
        diskExpiryThreadIntervalSeconds:執行disk終結執行緒的時間,預設為120秒
        memoryStoreEvictionPolicy:快取滿了之後的淘汰演算法
    快取子元素:
      cacheEventListenerFactory:註冊相應的的快取監聽類,用於處理快取事件,如put,remove,update,和expire
      bootstrapCacheLoaderFactory:指定相應的BootstrapCacheLoader,用於在初始化快取,以及自動設定。

同步的屬性說明:
 RMI快取分佈同步查詢 class使用net.sf.ehcache.distribution.RMICacheReplicatorFactory 
 Jroups快取同步查詢 class使用 net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory
 這個工廠支援以下屬性:
 replicatePuts=true | false – 當一個新元素增加到快取中的時候是否要複製到其他的peers。預設是true。
 replicateUpdates=true | false – 當一個已經在快取中存在的元素被覆蓋時是否要進行復制。預設是true。
 replicateRemovals= true | false – 當元素移除的時候是否進行復制。預設是true。
 replicateAsynchronously=true | false – 複製方式是非同步的指定為true時,還是同步的,指定為false時。預設是true。
 replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其他的cache中時是否進行復制指定為true時為複製,預設是true。
 replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其他的cache中時是否進行復制指定為true時為複製,預設是true。
 asynchronousReplicationIntervalMillis=1000


 原文地址及個人原始碼地址: http://www.dczou.com/viemall/209.html

 參考資料:http://www.ibm.com/developerworks/cn/java/j-lo-ehcache/
--------------------- 
作者:VieMall 
來源:CSDN 
原文:https://blog.csdn.net/tang06211015/article/details/52281551 
版權宣告:本文為博主原創文章,轉載請附上博文連結!