Ehcache分布式緩存
從1.2版本開(kāi)始,Ehcache可以使用分布式的緩存了。分布式這個(gè)特性是以plugin的方式實(shí)現(xiàn)的。Ehcache自帶了一些默認(rèn)的分布式緩存插件實(shí)現(xiàn),這些插件可以滿足大部分應(yīng)用的需要。如果需要使用其他的插件那就需要自己開(kāi)發(fā)了,開(kāi)發(fā)者可以通過(guò)查看distribution包里的源代碼及JavaDoc來(lái)實(shí)現(xiàn)它。
盡管不是必須的,在使用分布式緩存時(shí)理解一些ehcahce的設(shè)計(jì)思想也是有幫助的。這可以參看分布式緩存設(shè)計(jì)的頁(yè)面。
以下的部分將展示如何讓分布式插件同ehcache一起工作。
下面列出的是一些分布式緩存中比較重要的方面:
你如何知道集群環(huán)境中的其他緩存?分布式傳送的消息是什么形式?什么情況需要進(jìn)行復(fù)制?增加(Puts),更新(Updates)或是失效(Expiries)?采用什么方式進(jìn)行復(fù)制?同步還是異步方式?
為了安裝分布式緩存,你需要配置一個(gè)PeerProvider、一個(gè)CacheManagerPeerListener,它們對(duì)于一個(gè)CacheManager來(lái)說(shuō)是全局的。每個(gè)進(jìn)行分布式操作的cache都要添加一個(gè)cacheEventListener來(lái)傳送消息。
正確的元素類型
只有可序列化的元素可以進(jìn)行復(fù)制。
一些操作,比如移除,只需要元素的鍵值而不用整個(gè)元素;在這樣的操作中即使元素不是可序列化的但鍵值是可序列化的也可以被復(fù)制,
成員發(fā)現(xiàn)(Peer Discovery)
Ehcache進(jìn)行集群的時(shí)候有一個(gè)cache組的概念。每個(gè)cache都是其他cache的一個(gè)peer,沒(méi)有主cache的存在。剛才我們問(wèn)了一個(gè)問(wèn)題:你如何知道集群環(huán)境中的其他緩存?這個(gè)問(wèn)題可以命名為成員發(fā)現(xiàn)(Peer Discovery)。
Ehcache提供了兩種機(jī)制用來(lái)進(jìn)行成員發(fā)現(xiàn),就像一輛汽車:手動(dòng)檔和自動(dòng)檔。
要使用一個(gè)內(nèi)置的成員發(fā)現(xiàn)機(jī)制要在ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class屬性為net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。
自動(dòng)的成員發(fā)現(xiàn)
自動(dòng)的發(fā)現(xiàn)方式用TCP廣播機(jī)制來(lái)確定和維持一個(gè)廣播組。它只需要一個(gè)簡(jiǎn)單的配置可以自動(dòng)的在組中添加和移除成員。在集群中也不需要什么優(yōu)化服務(wù)器的知識(shí),這是默認(rèn)推薦的。
成員每秒向群組發(fā)送一個(gè)“心跳”。如果一個(gè)成員 5秒種都沒(méi)有發(fā)出信號(hào)它將被群組移除。如果一個(gè)新的成員發(fā)送了一個(gè)“心跳”它將被添加進(jìn)群組。
任何一個(gè)用這個(gè)配置安裝了復(fù)制功能的cache都將被其他的成員發(fā)現(xiàn)并標(biāo)識(shí)為可用狀態(tài)。
要設(shè)置自動(dòng)的成員發(fā)現(xiàn),需要指定ehcache配置文件中cacheManagerPeerProviderFactory元素的properties屬性,就像下面這樣:
peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port
# (timeToLive屬性詳見(jiàn)常見(jiàn)問(wèn)題部分的描述)
timeToLive=0-255
# (timeToLive屬性詳見(jiàn)常見(jiàn)問(wèn)題部分的描述)
timeToLive=0-255
示例
假設(shè)你在集群中有兩臺(tái)服務(wù)器。你希望同步sampleCache1和sampleCache2。每臺(tái)獨(dú)立的服務(wù)器都要有這樣的配置:
配置server1和server2
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
手動(dòng)進(jìn)行成員發(fā)現(xiàn)
進(jìn)行手動(dòng)成員配置要知道每個(gè)監(jiān)聽(tīng)器的IP地址和端口。成員不能在運(yùn)行時(shí)動(dòng)態(tài)地添加和移除。在技術(shù)上很難使用廣播的情況下就可以手動(dòng)成員發(fā)現(xiàn),例如在集群的服務(wù)器之間有一個(gè)不能傳送廣播報(bào)文的路由器。你也可以用手動(dòng)成員發(fā)現(xiàn)進(jìn)行單向的數(shù)據(jù)復(fù)制,只讓server2知道server1而server1不知道server2。
配置手動(dòng)成員發(fā)現(xiàn),需要指定ehcache配置文件中cacheManagerPeerProviderFactory的properties屬性,像下面這樣:
peerDiscovery=manual rmiUrls=//server:port/cacheName, 
rmiUrls配置的是服務(wù)器cache peers的列表。注意不要重復(fù)配置。

rmiUrls配置的是服務(wù)器cache peers的列表。注意不要重復(fù)配置。
示例
假設(shè)你在集群中有兩臺(tái)服務(wù)器。你要同步sampleCache1和sampleCache2。下面是每個(gè)服務(wù)器需要的配置:
配置server1
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
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"/>
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
配置CacheManagerPeerListener
每個(gè)CacheManagerPeerListener監(jiān)聽(tīng)成員們發(fā)向當(dāng)前CacheManager的消息。
配置CacheManagerPeerListener需要指定一個(gè)CacheManagerPeerListenerFactory,它以插件的機(jī)制實(shí)現(xiàn),用來(lái)創(chuàng)建CacheManagerPeerListener。
cacheManagerPeerListenerFactory的屬性有:
class – 一個(gè)完整的工廠類名。
properties – 只對(duì)這個(gè)工廠有意義的屬性,使用逗吃分隔。
Ehcache有一個(gè)內(nèi)置的基于RMI的分布系統(tǒng)。它的監(jiān)聽(tīng)器是RMICacheManagerPeerListener,這個(gè)監(jiān)聽(tīng)器可以用RMICacheManagerPeerListenerFactory來(lái)配置。
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001,
socketTimeoutMillis=2000"/>
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001,
socketTimeoutMillis=2000"/>
有效的屬性是:
hostname (可選) – 運(yùn)行監(jiān)聽(tīng)器的服務(wù)器名稱。標(biāo)明了做為集群群組的成員的地址,同時(shí)也是你想要控制的從集群中接收消息的接口。
在CacheManager初始化的時(shí)候會(huì)檢查hostname是否可用。
如果hostName不可用,CacheManager將拒絕啟動(dòng)并拋出一個(gè)連接被拒絕的異常。
如果指定,hostname將使用InetAddress.getLocalHost().getHostAddress()來(lái)得到。
警告:不要將localhost配置為本地地址127.0.0.1,因?yàn)樗诰W(wǎng)絡(luò)中不可見(jiàn)將會(huì)導(dǎo)致不能從遠(yuǎn)程服務(wù)器接收信息從而不能復(fù)制。在同一臺(tái)機(jī)器上有多個(gè)CacheManager的時(shí)候,你應(yīng)該只用localhost來(lái)配置。
port – 監(jiān)聽(tīng)器監(jiān)聽(tīng)的端口。
socketTimeoutMillis (可選) – Socket超時(shí)的時(shí)間。默認(rèn)是2000ms。
配置CacheReplicators
每個(gè)要進(jìn)行同步的cache都需要設(shè)置一個(gè)用來(lái)向CacheManagerr的成員復(fù)制消息的緩存事件監(jiān)聽(tīng)器。這個(gè)工作要通過(guò)為每個(gè)cache的配置增加一個(gè)cacheEventListenerFactory元素來(lái)完成。
<!-- 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>
<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:緩存名稱。通常為緩存對(duì)象的類名(非嚴(yán)格標(biāo)準(zhǔn))。
maxElementsInMemory:設(shè)置基于內(nèi)存的緩存可存放對(duì)象的最大數(shù)目。
maxElementsOnDisk:設(shè)置基于硬盤的緩存可存放對(duì)象的最大數(shù)目。
eternal:如果為true,表示對(duì)象永遠(yuǎn)不會(huì)過(guò)期,此時(shí)會(huì)忽略timeToIdleSeconds和timeToLiveSeconds屬性,默認(rèn)為false;
timeToIdleSeconds: 設(shè)定允許對(duì)象處于空閑狀態(tài)的最長(zhǎng)時(shí)間,以秒為單位。當(dāng)對(duì)象自從最近一次被訪問(wèn)后,如果處于空閑狀態(tài)的時(shí)間超過(guò)了timeToIdleSeconds屬性值,這個(gè)對(duì)象就會(huì)過(guò)期。當(dāng)對(duì)象過(guò)期,EHCache將把它從緩存中清空。只有當(dāng)eternal屬性為false,該屬性才有效。如果該屬性值為0,則表示對(duì)象可以無(wú)限期地處于空閑狀態(tài)。
timeToLiveSeconds:設(shè)定對(duì)象允許存在于緩存中的最長(zhǎng)時(shí)間,以秒為單位。當(dāng)對(duì)象自從被存放到緩存中后,如果處于緩存中的時(shí)間超過(guò)了 timeToLiveSeconds屬性值,這個(gè)對(duì)象就會(huì)過(guò)期。當(dāng)對(duì)象過(guò)期,EHCache將把它從緩存中清除。只有當(dāng)eternal屬性為false,該屬性才有效。如果該屬性值為0,則表示對(duì)象可以無(wú)限期地存在于緩存中。timeToLiveSeconds必須大于timeToIdleSeconds屬性,才有意義。
overflowToDisk:如果為true,表示當(dāng)基于內(nèi)存的緩存中的對(duì)象數(shù)目達(dá)到了maxElementsInMemory界限后,會(huì)把益出的對(duì)象寫到基于硬盤的緩存中。
class – 使用net.sf.ehcache.distribution.RMICacheReplicatorFactory
這個(gè)工廠支持以下屬性:
replicatePuts=true | false – 當(dāng)一個(gè)新元素增加到緩存中的時(shí)候是否要復(fù)制到其他的peers. 默認(rèn)是true。
replicateUpdates=true | false – 當(dāng)一個(gè)已經(jīng)在緩存中存在的元素被覆蓋時(shí)是否要進(jìn)行復(fù)制。默認(rèn)是true。
replicateRemovals= true | false – 當(dāng)元素移除的時(shí)候是否進(jìn)行復(fù)制。默認(rèn)是true。
replicateAsynchronously=true | false – 復(fù)制方式是異步的(指定為true時(shí))還是同步的(指定為false時(shí))。默認(rèn)是true。
replicateUpdatesViaCopy=true | false – 當(dāng)一個(gè)元素被拷貝到其他的cache中時(shí)是否進(jìn)行復(fù)制(指定為true時(shí)為復(fù)制),默認(rèn)是true。
你可以使用ehcache的默認(rèn)行為從而減少配置的工作量,默認(rèn)的行為是以異步的方式復(fù)制每件事;你可以像下面的例子一樣減少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>
<cache name="sampleCache4"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>
常見(jiàn)的問(wèn)題Windows上的Tomcat
有一個(gè)Tomcat或者是JDK的bug,在tomcat啟動(dòng)時(shí)如果tomcat的安裝路徑中有空格的話,在啟動(dòng)時(shí)RMI監(jiān)聽(tīng)器會(huì)失敗。參見(jiàn)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默認(rèn)是裝在“Program Files”文件夾里的,所以這個(gè)問(wèn)題經(jīng)常發(fā)生。
廣播阻斷
自動(dòng)的peer discovery與廣播息息相關(guān)。廣播可能被路由阻攔,像Xen和VMWare這種虛擬化的技術(shù)也可以阻攔廣播。如果這些都打開(kāi)了,你可能還在要將你的網(wǎng)卡的相關(guān)配置打開(kāi)。
一個(gè)簡(jiǎn)單的辦法可以告訴廣播是否有效,那就是使用ehcache remote debugger來(lái)看“心跳”是否可用。
廣播傳播的不夠遠(yuǎn)或是傳得太遠(yuǎn)
你可以通過(guò)設(shè)置badly misnamed time to live來(lái)控制廣播傳播的距離。用廣播IP協(xié)議時(shí),timeToLive的值指的是數(shù)據(jù)包可以傳遞的域或是范圍。約定如下:
0是限制在同一個(gè)服務(wù)器
1是限制在同一個(gè)子網(wǎng)
32是限制在同一個(gè)網(wǎng)站
64是限制在同一個(gè)region
128是限制在同一個(gè)大洲
255是不限制
譯者按:上面這些資料翻譯的不夠準(zhǔn)確,請(qǐng)讀者自行尋找原文理解吧。
在Java實(shí)現(xiàn)中默認(rèn)值是1,也就是在同一個(gè)子網(wǎng)中傳播。改變timeToLive屬性可以限制或是擴(kuò)展傳播的范圍。
原文地址為 http://ehcache.sourceforge.net/documentation/distributed_caching.html
posted on 2012-02-14 15:46 paulwong 閱讀(9004) 評(píng)論(2) 編輯 收藏 所屬分類: 緩存