ehcache之RMI集群配置
EhCache 是一個純 Java 的進程內緩存框架,具有快速、精干等特點,是 Hibernate 中默認的 CacheProvider。
ehcache架構圖:
由于 EhCache是進程中的緩存系統,一旦將應用部署在集群環境中,每一個節點維護各自的緩存數據,當某個節點對緩存數據進行更新,這些更新的數據無法在其它節點中共享,這不僅會降低節點運行的效率,而且會導致數據不同步的情況發生。例如某個網站采用 A、B 兩個節點作為集群部署,當 A 節點的緩存更新后,而 B 節點緩存尚未更新就可能出現用戶在瀏覽頁面的時候,一會是更新后的數據,一會是尚未更新的數據,盡管我們也可以通過 Session Sticky 技術來將用戶鎖定在某個節點上,但對于一些交互性比較強或者是非 Web 方式的系統來說,Session Sticky 顯然不太適合。所以就需要用到 EhCache 的集群解決方案。
EhCache 從 1.7 版本開始,支持五種集群方案,分別是:
- Terracotta
- RMI
- JMS
- JGroups
- EhCache Server </ul>
本文主要介紹RMI集群方式:
RMI 是 Java 的一種遠程方法調用技術,是一種點對點的基于 Java 對象的通訊方式。EhCache 從 1.2 版本開始就支持 RMI 方式的緩存集群。在集群環境中 EhCache 所有緩存對象的鍵和值都必須是可序列化的,也就是必須實現 java.io.Serializable 接口,這點在其它集群方式下也是需要遵守的。

采用 RMI 集群模式時,集群中的每個節點都是對等關系,并不存在主節點或者從節點的概念,因此節點間必須有一個機制能夠互相認識對方,必須知道其它節點的信息,包括主機地址、端口號等。EhCache 提供兩種節點的發現方式:手工配置和自動發現。手工配置方式要求在每個節點中配置其它所有節點的連接信息,一旦集群中的節點發生變化時,需要對緩存進行重新配置。
由于 RMI 是 Java 中內置支持的技術,因此使用 RMI 集群模式時,無需引入其它的 Jar 包,EhCache 本身就帶有支持 RMI 集群的功能。使用 RMI 集群模式需要在 ehcache.xml 配置文件中定義 cacheManagerPeerProviderFactory 節點。假設集群中有兩個節點,分別對應的 RMI 綁定信息是:
【節點A 192.168.0.100 userCache | 節點B 192.168.0.101 userCache】
RMI支持兩種緩存復制機制,一種為點對點復制,即指定集群中其他節點信息,另一種為組播復制,即單節點廣播緩存數據,其他節點接受廣播并更新緩存。
首先介紹點對點復制
需要在ehcache.xml中添加如下配置信息:
<cacheManagerPeerProviderFactory
class=”net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory”
properties=”peerDiscovery=manual,
rmiUrls=//192.168.0.100:40001/userCache” /><!– 緩存同步監聽端口 –> <cacheManagerPeerListenerFactory class=”net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory” properties=”hostName=localhost,port=40001, socketTimeoutMillis=2000″ /> <defaultCache maxElementsInMemory=”10000″ eternal=”false” timeToIdleSeconds=”300″ timeToLiveSeconds=”300″ overflowToDisk=”false”> <cacheEventListenerFactory class=”net.sf.ehcache.distribution.RMICacheReplicatorFactory” properties=”replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true” /> </defaultCache> </pre><br />
rmiUrls為當前節點緩存更新后需要將緩存復制到的目標節點,如果多個,則使用“|”分割,userCache為緩存塊名(注意,如果是mybatis中使用,此處應該為mapper的namespace名稱)。另外一個節點只需要修改rmiUrls列表即可。
replicateAsynchronously 對象同步是否異步完成,默認為true。如果比較緊急就設為false。 在一致性時間性要求不強的時候,設為異步可大大提供性能,因為它是異步立即返回的,而且可以批量提交。
replicateUpdatesViaCopy 是否將對象變更復制到所有節點,還是只是發送一個失效信息,讓對方該緩存失效,當對方需要該緩存時重新計算載入。
默認為true。鑒于對象復制的消耗挺大的,又有鎖的問題,而且對方也未必需要該對象,所以此屬性建議設為false。如果業務上真的需要設為true時,就可考慮使用Terracotta了。
replicatePuts、replicateUpdates、replicateRemovals 增刪改是否同步,默認都為true。但因為我們前面選擇了失效算法,所以replicatePuts 要設為false。從以上配置可明顯看出,點對點緩存復制更新的缺點,如果有N多個集群幾點,每個配置都需要修改。
另外一種復制方式:組播通知復制,配置如下:
<cacheManagerPeerProviderFactory
class=”net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory”
properties=”peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4006, timeToLive=32″
/><cacheManagerPeerListenerFactory class=”net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory” /> <defaultCache maxElementsInMemory=”10000″ eternal=”false” timeToIdleSeconds=”0″ timeToLiveSeconds=”0″ overflowToDisk=”false”> <cacheEventListenerFactory class=”net.sf.ehcache.distribution.RMICacheReplicatorFactory” properties=”replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=true, replicateRemovals=true” /> </defaultCache> </pre><br />
peerDiscovery為automatic,自動發現網絡中各個節點,multicastGroupAddress為IP地址中D類地址(224.0.1.0 到 238.255.255.255 )中任意一個即可。此時即完成配置。
組播方式優勢很明顯,即不管多少個集群,配置都相同,不需要做任何修改,但是也有明顯的缺點,數據不能跨網段傳輸;如果網絡環境比較復雜的話,數據更容易丟失,無法實現緩存復制等。
總結:RMI集群配置支持兩種緩存復制策略,即點對點復制和組播復制,點對點復制如果對于大型機群環境,配置問題難免是一體力活;組播方式可解決點對點復制配置復雜的問題,但是如果網絡環境比較復雜的情況下,節點間緩存可能無法復制,所以根據個人的網絡環境及集群數量,可選擇一種更好的方式來配置緩存。
附:關于EhCache中timeToLiveSeconds, timeToIdleSeconds說明:http://blog.csdn.net/vtopqx/article/details/8522333
參考:http://www.ibm.com/developerworks/cn/java/j-lo-ehcache/
http://ehcache.org/documentation/2.8/replication/rmi-replicated-caching