從1.2版本開始,Ehcache可以使用分布式的緩存了。
分布式這個特性是以plugin的方式實現的。Ehcache自帶了一些默認的分布式緩存插件實現,這些插件可以滿足大部分應用的需要。如果需要使用其他的插件那就需要自己開發了,開發者可以通過查看distribution包里的源代碼及JavaDoc來實現它。
盡管不是必須的,在使用分布式緩存時理解一些ehcahce的設計思想也是有幫助的。這可以參看分布式緩存設計的頁面。
以下的部分將展示如何讓分布式插件同ehcache一起工作。
下面列出的是一些分布式緩存中比較重要的方面:
你如何知道集群環境中的其他緩存?分布式傳送的消息是什么形式?什么情況需要進行復制?增加(Puts),更新(Updates)或是失效(Expiries)?采用什么方式進行復制?同步還是異步方式?
為了安裝分布式緩存,你需要配置一個PeerProvider、一個CacheManagerPeerListener,它們對于一個CacheManager來說是全局的。每個進行分布式操作的cache都要添加一個cacheEventListener來傳送消息。
正確的元素類型
只有可序列化的元素可以進行復制。
一些操作,比如移除,只需要元素的鍵值而不用整個元素;在這樣的操作中即使元素不是可序列化的但鍵值是可序列化的也可以被復制,
成員發現(Peer Discovery)
Ehcache進行集群的時候有一個cache組的概念。每個cache都是其他cache的一個peer,沒有主cache的存在。剛才我們問了一個問題:你如何知道集群環境中的其他緩存?這個問題可以命名為成員發現(Peer Discovery)。
Ehcache提供了兩種機制用來進行成員發現,就像一輛汽車:手動檔和自動檔。
要使用一個內置的成員發現機制要在ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class屬性為net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。
自動的成員發現
自動的發現方式用TCP廣播機制來確定和維持一個廣播組。它只需要一個簡單的配置可以自動的在組中添加和移除成員。在集群中也不需要什么優化服務器的知識,這是默認推薦的。
成員每秒向群組發送一個“心跳”。如果一個成員 5秒種都沒有發出信號它將被群組移除。如果一個新的成員發送了一個“心跳”它將被添加進群組。
任何一個用這個配置安裝了復制功能的cache都將被其他的成員發現并標識為可用狀態。
要設置自動的成員發現,需要指定ehcache配置文件中cacheManagerPeerProviderFactory元素的properties屬性,就像下面這樣:
peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port
# (timeToLive屬性詳見常見問題部分的描述)
timeToLive=0-255
示例
假設你在集群中有兩臺服務器。你希望同步sampleCache1和sampleCache2。每臺獨立的服務器都要有這樣的配置:
配置server1和server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
手動進行成員發現
進行手動成員配置要知道每個監聽器的IP地址和端口。成員不能在運行時動態地添加和移除。在技術上很難使用廣播的情況下就可以手動成員發現,例如在集群的服務器之間有一個不能傳送廣播報文的路由器。你也可以用手動成員發現進行單向的數據復制,只讓server2知道server1而server1不知道server2。
配置手動成員發現,需要指定ehcache配置文件中cacheManagerPeerProviderFactory的properties屬性,像下面這樣:
peerDiscovery=manual rmiUrls=//server:port/cacheName, 
rmiUrls配置的是服務器cache peers的列表。注意不要重復配置。
示例
假設你在集群中有兩臺服務器。你要同步sampleCache1和sampleCache2。下面是每個服務器需要的配置:
配置server1
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
配置server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
配置CacheManagerPeerListener
每個CacheManagerPeerListener監聽成員們發向當前CacheManager的消息。
配置CacheManagerPeerListener需要指定一個CacheManagerPeerListenerFactory,它以插件的機制實現,用來創建CacheManagerPeerListener。
cacheManagerPeerListenerFactory的屬性有:
class – 一個完整的工廠類名。
properties – 只對這個工廠有意義的屬性,使用逗吃分隔。
Ehcache有一個內置的基于RMI的分布系統。它的監聽器是RMICacheManagerPeerListener,這個監聽器可以用RMICacheManagerPeerListenerFactory來配置。
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001,
socketTimeoutMillis=2000"/>
有效的屬性是:
hostname (可選) – 運行監聽器的服務器名稱。標明了做為集群群組的成員的地址,同時也是你想要控制的從集群中接收消息的接口。
在CacheManager初始化的時候會檢查hostname是否可用。
如果hostName不可用,CacheManager將拒絕啟動并拋出一個連接被拒絕的異常。
如果指定,hostname將使用InetAddress.getLocalHost().getHostAddress()來得到。
警告:不要將localhost配置為本地地址127.0.0.1,因為它在網絡中不可見將會導致不能從遠程服務器接收信息從而不能復制。在同一臺機器上有多個CacheManager的時候,你應該只用localhost來配置。
port – 監聽器監聽的端口。
socketTimeoutMillis (可選) – Socket超時的時間。默認是2000ms。
配置CacheReplicators
每個要進行同步的cache都需要設置一個用來向CacheManagerr的成員復制消息的緩存事件監聽器。這個工作要通過為每個cache的配置增加一個cacheEventListenerFactory元素來完成。
<!-- Sample cache named sampleCache2. -->
<cache name="sampleCache2"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true "/>
</cache>
name:緩存名稱。通常為緩存對象的類名(非嚴格標準)。
maxElementsInMemory:設置基于內存的緩存可存放對象的最大數目。
maxElementsOnDisk:設置基于硬盤的緩存可存放對象的最大數目。
eternal:如果為true,表示對象永遠不會過期,此時會忽略timeToIdleSeconds和timeToLiveSeconds屬性,默認為false;
timeToIdleSeconds: 設定允許對象處于空閑狀態的最長時間,以秒為單位。當對象自從最近一次被訪問后,如果處于空閑狀態的時間超過了timeToIdleSeconds屬性值,這個對象就會過期。當對象過期,EHCache將把它從緩存中清空。只有當eternal屬性為false,該屬性才有效。如果該屬性值為0,則表示對象可以無限期地處于空閑狀態。
timeToLiveSeconds:設定對象允許存在于緩存中的最長時間,以秒為單位。當對象自從被存放到緩存中后,如果處于緩存中的時間超過了 timeToLiveSeconds屬性值,這個對象就會過期。當對象過期,EHCache將把它從緩存中清除。只有當eternal屬性為false,該屬性才有效。如果該屬性值為0,則表示對象可以無限期地存在于緩存中。timeToLiveSeconds必須大于timeToIdleSeconds屬性,才有意義。
overflowToDisk:如果為true,表示當基于內存的緩存中的對象數目達到了maxElementsInMemory界限后,會把益出的對象寫到基于硬盤的緩存中。
class – 使用net.sf.ehcache.distribution.RMICacheReplicatorFactory
這個工廠支持以下屬性:
replicatePuts=true | false – 當一個新元素增加到緩存中的時候是否要復制到其他的peers. 默認是true。
replicateUpdates=true | false – 當一個已經在緩存中存在的元素被覆蓋時是否要進行復制。默認是true。
replicateRemovals= true | false – 當元素移除的時候是否進行復制。默認是true。
replicateAsynchronously=true | false – 復制方式是異步的(指定為true時)還是同步的(指定為false時)。默認是true。
replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其他的cache中時是否進行復制(指定為true時為復制),默認是true。
你可以使用ehcache的默認行為從而減少配置的工作量,默認的行為是以異步的方式復制每件事;你可以像下面的例子一樣減少RMICacheReplicatorFactory的屬性配置:
<!-- Sample cache named sampleCache4. All missing RMICacheReplicatorFactory properties default to true -->
<cache name="sampleCache4"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>
常見的問題Windows上的Tomcat
有一個Tomcat或者是JDK的bug,在tomcat啟動時如果tomcat的安裝路徑中有空格的話,在啟動時RMI監聽器會失敗。參見http://archives.java.sun.com/cgi-bin/wa?A2=ind0205&L=rmi-users&P=797和http://www.ontotext.com/kim/doc/sys-doc/faq-howto-bugs/known-bugs.html。
由于在Windows上安裝Tomcat默認是裝在“Program Files”文件夾里的,所以這個問題經常發生。
廣播阻斷
自動的peer discovery與廣播息息相關。廣播可能被路由阻攔,像Xen和VMWare這種虛擬化的技術也可以阻攔廣播。如果這些都打開了,你可能還在要將你的網卡的相關配置打開。
一個簡單的辦法可以告訴廣播是否有效,那就是使用ehcache remote debugger來看“心跳”是否可用。
廣播傳播的不夠遠或是傳得太遠
你可以通過設置badly misnamed time to live來控制廣播傳播的距離。用廣播IP協議時,timeToLive的值指的是數據包可以傳遞的域或是范圍。約定如下:
0是限制在同一個服務器
1是限制在同一個子網
32是限制在同一個網站
64是限制在同一個region
128是限制在同一個大洲
255是不限制
譯者按:上面這些資料翻譯的不夠準確,請讀者自行尋找原文理解吧。
在Java實現中默認值是1,也就是在同一個子網中傳播。改變timeToLive屬性可以限制或是擴展傳播的范圍。
原文地址為 http://ehcache.sourceforge.net/documentation/distributed_caching.html