開發環境:html
System:Windowsjava
JavaEE Server:tomcat5.0.2.八、tomcat6算法
JavaSDK: jdk6+編程
IDE:eclipse、MyEclipse 6.6bootstrap
開發依賴庫:緩存
JDK六、 JavaEE五、ehcache-core-2.5.2.jartomcat
Email:hoojo_@126.com安全
Blog:http://blog.csdn.net/IBM_hoojo服務器
前面2篇文章介紹到Ehcache 整合Spring 使用頁面、對象緩存 http://www.cnblogs.com/hoojo/archive/2012/07/12/2587556.html
在Spring、Hibernate中使用Ehcache緩存 http://www.cnblogs.com/hoojo/archive/2012/07/12/2587941.html
1、緩存系統簡介
EhCache 是一個純 Java 的進程內緩存框架,具備快速、精幹等特色,是 Hibernate 中默認的 CacheProvider。
EhCache 應用架構圖,下圖是 EhCache 在應用程序中的位置:
EhCache 的主要特性有:
1. 快速、精幹;
2. 簡單;
3. 多種緩存策略;
4. 緩存數據有兩級:內存和磁盤,所以無需擔憂容量問題;
5. 緩存數據會在虛擬機重啓的過程當中寫入磁盤;
6. 能夠經過 RMI、可插入 API 等方式進行分佈式緩存;
7. 具備緩存和緩存管理器的偵聽接口;
8. 支持多緩存管理器實例,以及一個實例的多個緩存區域;
9. 提供 Hibernate 的緩存實現;
因爲 EhCache 是進程中的緩存系統,一旦將應用部署在集羣環境中,每個節點維護各自的緩存數據,當某個節點對緩存數據進行更新,這些更新的數據沒法在其它節點中共享,這不只會下降節點運行的效率,並且會致使數據不一樣步的狀況發生。例如某個網站採用 A、B 兩個節點做爲集羣部署,當 A 節點的緩存更新後,而 B 節點緩存還沒有更新就可能出現用戶在瀏覽頁面的時候,一會是更新後的數據,一會是還沒有更新的數據,儘管咱們也能夠經過 Session Sticky 技術來將用戶鎖定在某個節點上,但對於一些交互性比較強或者是非 Web 方式的系統來講,Session Sticky 顯然不太適合。
因此就須要用到 EhCache 的集羣解決方案。
從1.2版本開始,Ehcache可使用分佈式的緩存了。EhCache 從 1.7 版本開始,支持五種集羣方案,分別是:
• Terracotta
• RMI
• JMS
• JGroups
• EhCache Server
其中的三種最爲經常使用集羣方式,分別是 RMI、JGroups 以及 EhCache Server 。本文主要介紹RMI的方式。
分佈式這個特性是以plugin的方式實現的。Ehcache自帶了一些默認的分佈式緩存插件實現,這些插件能夠知足大部分應用的須要。若是須要使用其餘的插件那就須要本身開發了,開發者能夠經過查看distribution包裏的源代碼及JavaDoc來實現它。儘管不是必須的,在使用分佈式緩存時理解一些ehcahce的設計思想也是有幫助的。這能夠參看分佈式緩存設計的頁面。如下的部分將展現如何讓分佈式插件同ehcache一塊兒工做。
下面列出的是一些分佈式緩存中比較重要的方面:
• 你如何知道集羣環境中的其餘緩存?
• 分佈式傳送的消息是什麼形式?
• 什麼狀況須要進行復制?增長(Puts),更新(Updates)或是失效(Expiries)?
• 採用什麼方式進行復制?同步仍是異步方式?
爲了安裝分佈式緩存,你須要配置一個PeerProvider、一個CacheManagerPeerListener,
它們對於一個CacheManager來講是全局的。每一個進行分佈式操做的cache都要添加一個cacheEventListener來傳送消息。
2、集羣緩存概念及其配置
只有可序列化的元素能夠進行復制。一些操做,好比移除,只須要元素的鍵值而不用整個元素;在這樣的操做中即便元素不是可序列化的但鍵值是可序列化的也能夠被複制。
Ehcache進行集羣的時候有一個cache組的概念。每一個cache都是其餘cache的一個peer,沒有主cache的存在。剛纔咱們問了一個問題:你如何知道集羣環境中的其餘緩存?這個問題能夠命名爲成員發現(Peer Discovery)。
Ehcache提供了兩種機制用來進行成員發現,就像一輛汽車:手動檔和自動檔。要使用一個內置的成員發現機制要在ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class屬性爲
net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。
自動的發現方式用TCP廣播機制來肯定和維持一個廣播組。它只須要一個簡單的配置能夠自動的在組中添加和移除成員。在集羣中也不須要什麼優化服務器的知識,這是默認推薦的。
成員每秒向羣組發送一個「心跳」。若是一個成員 5秒種都沒有發出信號它將被羣組移除。若是一個新的成員發送了一個「心跳」它將被添加進羣組。
任何一個用這個配置安裝了複製功能的cache都將被其餘的成員發現並標識爲可用狀態。
要設置自動的成員發現,須要指定ehcache配置文件中cacheManagerPeerProviderFactory元素的properties屬性,就像下面這樣:
peerDiscovery=automaticmulticastGroupAddress=multicast address | multicast host name
multicastGroupPort=port
timeToLive=0-255 (timeToLive屬性詳見常見問題部分的描述)
假設你在集羣中有兩臺服務器。你但願同步sampleCache1和sampleCache2。每臺獨立的服務器都要有這樣的配置:
配置server1和server2<cacheManagerPeerProviderFactoryclass="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, //server:port/cacheName ...
rmiUrls配置的是服務器cache peers的列表。注意不要重複配置。
假設你在集羣中有兩臺服務器。你要同步sampleCache1和sampleCache2。下面是每一個服務器須要的配置:
配置server1<cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="peerDiscovery=manual,rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
配置server2
<cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="peerDiscovery=manual,rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
每一個CacheManagerPeerListener監遵從成員們發向當前CacheManager的消息。配置CacheManagerPeerListener須要指定一個CacheManagerPeerListenerFactory,它以插件的機制實現,用來建立CacheManagerPeerListener。
cacheManagerPeerListenerFactory的屬性有:
class – 一個完整的工廠類名。
properties – 只對這個工廠有意義的屬性,使用逗號分隔。Ehcache有一個內置的基於RMI的分佈系統。它的監聽器是RMICacheManagerPeerListener,這個監聽器能夠用
RMICacheManagerPeerListenerFactory來配置。
<cacheManagerPeerListenerFactoryclass="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。當你socket同步緩存請求地址比較遠,不是本地局域網。你可能須要把這個時間配置大些,否則極可能延時致使同步緩存失敗。
每一個要進行同步的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>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。
replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其餘的cache中時是否進行復制指定爲true時爲複製,默認是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>
有一個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屬性能夠限制或是擴展傳播的範圍。
3、 RMI方式緩存集羣/配置分佈式緩存
RMI 是 Java 的一種遠程方法調用技術,是一種點對點的基於 Java 對象的通信方式。EhCache 從 1.2 版本開始就支持 RMI 方式的緩存集羣。在集羣環境中 EhCache 全部緩存對象的鍵和值都必須是可序列化的,也就是必須實現 java.io.Serializable 接口,這點在其它集羣方式下也是須要遵照的。
下圖是 RMI 集羣模式的結構圖:
採用 RMI 集羣模式時,集羣中的每一個節點都是對等關係,並不存在主節點或者從節點的概念,所以節點間必須有一個機制可以互相認識對方,必須知道其它節點的信息,包括主機地址、端口號等。EhCache 提供兩種節點的發現方式:手工配置和自動發現。手工配置方式要求在每一個節點中配置其它全部節點的鏈接信息,一旦集羣中的節點發生變化時,須要對緩存進行從新配置。
因爲 RMI 是 Java 中內置支持的技術,所以使用 RMI 集羣模式時,無需引入其它的 Jar 包,EhCache 自己就帶有支持 RMI 集羣的功能。使用 RMI 集羣模式須要在 ehcache.xml 配置文件中定義 cacheManagerPeerProviderFactory 節點。
分佈式同步緩存要讓這邊的cache知道對方的cache,叫作Peer Discovery(成員發現) EHCache實現成員發現的方式有兩種:
一、手動查找
A、 在ehcache.xml中配置PeerDiscovery成員發現對象
Server1配置,配置本地hostName、port是400001,分別監聽192.168.8.32:400002的mobileCache和192.168.5.231:400003 的mobileCache。注意這裏的mobileCache是緩存的名稱,分別對應着server二、server3的cache的配置。
<?xml version="1.0" encoding="gbk"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"><diskStore path="java.io.tmpdir"/><!--集羣多臺服務器中的緩存,這裏是要同步一些服務器的緩存server1 hostName:192.168.8.9 port:400001 cacheName:mobileCacheserver2 hostName:192.168.8.32 port:400002 cacheName:mobileCacheserver3 hostName:192.168.8.231 port:400003 cacheName:mobileCache注意:每臺要同步緩存的服務器的RMI通訊socket端口都不同,在配置的時候注意設置--><!-- server1 的cacheManagerPeerProviderFactory配置 --><cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="hostName=localhost,port=400001,socketTimeoutMillis=2000,peerDiscovery=manual,rmiUrls=//192.168.8.32:400002/mobileCache|//192.168.5.231:400003/mobileCache"/></ehcache>以上注意cacheManagerPeerProviderFactory元素出現的位置在diskStore下
一樣在你的另外2臺服務器上增長配置
Server2,配置本地host,port爲400002,分別同步192.168.8.9:400001的mobileCache和192.168.5.231:400003的mobileCache
<!-- server2 的cacheManagerPeerProviderFactory配置 --><cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="hostName=localhost,port=400002,socketTimeoutMillis=2000,peerDiscovery=manual,rmiUrls=//192.168.8.9:400001/mobileCache|//192.168.5.231:400003/mobileCache"/>Server3,配置本地host,port爲400003,分別同步192.168.8.9:400001的mobileCache緩存和192.168.8.32:400002的mobileCache緩存
<!-- server3 的cacheManagerPeerProviderFactory配置 --><cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="hostName=localhost,port=400003,socketTimeoutMillis=2000,peerDiscovery=manual,rmiUrls=//192.168.8.9:400001/mobileCache|//192.168.8.32:400002/mobileCache"/>這樣就在三臺不一樣的服務器上配置了手動查找cache的PeerProvider成員發現的配置了。 值得注意的是你在配置rmiUrls的時候要特別注意url不能重複出現,而且端口、地址都是對的。
若是指定,hostname將使用InetAddress.getLocalHost().getHostAddress()來獲得。
警告:不要將localhost配置爲本地地址127.0.0.1,由於它在網絡中不可見將會致使不能從遠程服務器接收信息從而不能複製。在同一臺機器上有多個CacheManager的時候,你應該只用localhost來配置。
B、 下面配置緩存和緩存同步監聽,須要在每臺服務器中的ehcache.xml文件中增長cache配置和cacheEventListenerFactory、cacheLoaderFactory的配置
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false"/><!--配置自定義緩存maxElementsInMemory:緩存中容許建立的最大對象數eternal:緩存中對象是否爲永久的,若是是,超時設置將被忽略,對象從不過時。timeToIdleSeconds:緩存數據空閒的最大時間,也就是說若是有一個緩存有多久沒有被訪問就會被銷燬,若是該值是 0 就意味着元素能夠停頓無窮長的時間。timeToLiveSeconds:緩存數據存活的時間,緩存對象最大的的存活時間,超過這個時間就會被銷燬,這隻能在元素不是永久駐留時有效,若是該值是0就意味着元素能夠停頓無窮長的時間。overflowToDisk:內存不足時,是否啓用磁盤緩存。memoryStoreEvictionPolicy:緩存滿了以後的淘汰算法。每個小時更新一次緩存(1小時過時)--><cache name="mobileCache"maxElementsInMemory="10000"eternal="false"overflowToDisk="true"timeToIdleSeconds="1800"timeToLiveSeconds="3600"memoryStoreEvictionPolicy="LFU"><!--RMI緩存分佈同步查找 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。replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其餘的cache中時是否進行復制指定爲true時爲複製,默認是true。replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其餘的cache中時是否進行復制指定爲true時爲複製,默認是true。asynchronousReplicationIntervalMillis=1000--><!-- 監聽RMI同步緩存對象配置 註冊相應的的緩存監聽類,用於處理緩存事件,如put,remove,update,和expire --><cacheEventListenerFactoryclass="net.sf.ehcache.distribution.RMICacheReplicatorFactory"properties="replicateAsynchronously=true,replicatePuts=true,replicateUpdates=true,replicateUpdatesViaCopy=false,replicateRemovals=true "/><!-- 用於在初始化緩存,以及自動設置 --><bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/></cache>
C、 這樣就完成了3臺服務器的配置,下面給出server1的完整的ehcache.xml的配置
<?xml version="1.0" encoding="gbk"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"><diskStore path="java.io.tmpdir"/><!--集羣多臺服務器中的緩存,這裏是要同步一些服務器的緩存server1 hostName:192.168.8.9 port:400001 cacheName:mobileCacheserver2 hostName:192.168.8.32 port:400002 cacheName:mobileCacheserver3 hostName:192.168.8.231 port:400003 cacheName:mobileCache注意每臺要同步緩存的服務器的RMI通訊socket端口都不同,在配置的時候注意設置--><!-- server1 的cacheManagerPeerProviderFactory配置 --><cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="hostName=localhost,port=400001,socketTimeoutMillis=2000,peerDiscovery=manual,rmiUrls=//192.168.8.32:400002/mobileCache|//192.168.5.231:400003/mobileCache"/><defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false"/><!--配置自定義緩存maxElementsInMemory:緩存中容許建立的最大對象數eternal:緩存中對象是否爲永久的,若是是,超時設置將被忽略,對象從不過時。timeToIdleSeconds:緩存數據空閒的最大時間,也就是說若是有一個緩存有多久沒有被訪問就會被銷燬,若是該值是 0 就意味着元素能夠停頓無窮長的時間。timeToLiveSeconds:緩存數據存活的時間,緩存對象最大的的存活時間,超過這個時間就會被銷燬,這隻能在元素不是永久駐留時有效,若是該值是0就意味着元素能夠停頓無窮長的時間。overflowToDisk:內存不足時,是否啓用磁盤緩存。memoryStoreEvictionPolicy:緩存滿了以後的淘汰算法。每個小時更新一次緩存(1小時過時)--><cache name="mobileCache"maxElementsInMemory="10000"eternal="false"overflowToDisk="true"timeToIdleSeconds="1800"timeToLiveSeconds="3600"memoryStoreEvictionPolicy="LFU"><!--RMI緩存分佈同步查找 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。replicatePutsViaCopy=true | false – 當一個新增元素被拷貝到其餘的cache中時是否進行復制指定爲true時爲複製,默認是true。replicateUpdatesViaCopy=true | false – 當一個元素被拷貝到其餘的cache中時是否進行復制指定爲true時爲複製,默認是true。asynchronousReplicationIntervalMillis=1000--><!-- 監聽RMI同步緩存對象配置 註冊相應的的緩存監聽類,用於處理緩存事件,如put,remove,update,和expire --><cacheEventListenerFactoryclass="net.sf.ehcache.distribution.RMICacheReplicatorFactory"properties="replicateAsynchronously=true,replicatePuts=true,replicateUpdates=true,replicateUpdatesViaCopy=false,replicateRemovals=true "/><!-- 用於在初始化緩存,以及自動設置 --><bootstrapCacheLoaderFactory class="net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory"/></cache></ehcache>
二、自動發現
自動發現配置和手動查找的方式有一點不一樣,其餘的地方都基本是同樣的。一樣在ehcache.xml中增長配置,配置以下
<!--搜索某個網段上的緩存timeToLive0是限制在同一個服務器1是限制在同一個子網32是限制在同一個網站64是限制在同一個region128是限制在同一個大洲255是不限制--><cacheManagerPeerProviderFactoryclass="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"properties="peerDiscovery=automatic, multicastGroupAddress=192.168.0.1,multicastGroupPort=400004, timeToLive=32"/>其餘的配置和手動查找方式的配置是同樣的,這裏就再也不贅述了。關於ehcache的其餘緩存配置方式這裏將再也不介紹,你們能夠本身去研究。能夠參考:
官方文檔:http://www.ehcache.org/documentation/user-guide/cache-topologies#using-a-cache-server
ibm developerworks文檔:http://www.ibm.com/developerworks/cn/java/j-lo-ehcache/index.html
EhCache 從 1.5. 版本開始增長了 JGroups 的分佈式集羣模式。與 RMI 方式相比較, JGroups 提供了一個很是靈活的協議棧、可靠的單播和多播消息傳輸,主要的缺點是配置複雜以及一些協議棧對第三方包的依賴。
JGroups 也提供了基於 TCP 的單播 ( Unicast ) 和基於 UDP 的多播 ( Multicast ) ,對應 RMI 的手工配置和自動發現。使用單播方式須要指定其它節點的主機地址和端口,下面是兩個節點,並使用了單播方式的配置:
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" properties="connect=TCP(start_port=7800): TCPPING(initial_hosts=host1[7800],host2[7800];port_range=10;timeout=3000; num_initial_members=3;up_thread=true;down_thread=true): VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false): pbcast.NAKACK(down_thread=true;up_thread=true;gc_lag=100; retransmit_timeout=3000): pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false; print_local_addr=false;down_thread=true;up_thread=true)" propertySeparator="::" />
使用多播方式配置以下:
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;):PING: MERGE2:FD_SOCK:VERIFY_SUSPECT:pbcast.NAKACK:UNICAST:pbcast.STABLE:FRAG:pbcast.GMS" propertySeparator="::" />
從上面的配置來看,JGroups 的配置要比 RMI 複雜得多,但也提供更多的微調參數,有助於提高緩存數據複製的性能。詳細的 JGroups 配置參數的具體意義可參考 JGroups 的配置手冊。
JGroups 方式對應緩存節點的配置信息以下:
<cache name="sampleCache2" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="100" timeToLiveSeconds="100" overflowToDisk="false"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" /> </cache>
使用 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
通過實際測試發現,集羣方式下的緩存數據均可以在 1 秒鐘以內完成到其節點的複製。
與前面介紹的兩種集羣方案不一樣的是, 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 在應用中的架構:
EhCache Server 同時也提供強大的安全機制、監控功能。在數據存儲方面,最大的 Ehcache 單實例在內存中能夠緩存 20GB。最大的磁盤能夠緩存 100GB。經過將節點整合在一塊兒,這樣緩存數據就能夠跨越節點,以此得到更大的容量。將緩存 20GB 的 50 個節點整合在一塊兒就是 1TB 了。
以上咱們介紹了三種 EhCache 的集羣方案,除了第三種跨編程語言的方案外,EhCache 的集羣對應用程序的代碼編寫都是透明的,程序人員無需考慮緩存數據是如何複製到其它節點上。既保持了代碼的輕量級,同時又支持龐大的數據集羣。EhCache 可謂是深刻人心。
2009 年年中,Terracotta 宣佈收購 EhCache 產品。Terracotta 公司的產品 Terracotta 是一個 JVM 級的開源羣集框架,提供 HTTP Session 複製、分佈式緩存、POJO 羣集、跨越集羣的 JVM 來實現分佈式應用程序協調。最近 EhCache 主要的改進都集中在跟 Terracotta 框架的集成上,這是一個真正意義上的企業級緩存解決方案。
=======================================================================
ehcache提供三種網絡鏈接策略來實現集羣,rmi,jgroup還有jms。同時ehcache能夠能夠實現多播的方式實現集羣,也能夠手動指定集羣主機序列實現集羣
Ehcache支持的分佈式緩存支持有三種RMI,JGroups,JMS,這裏介紹下MRI和JGrpups兩種方式,Ehcache使用版本爲1.5.0,關於ehcache的其餘信息請參http://ehcache.sourceforge.net/EhcacheUserGuide.html,
關於jgroups的信息請參考http://www.jgroups.org/manual/html_single/index.html。
環境爲兩臺機器 server1 ip:192.168.2.154,server2 ip:192.168.2.23
rmi的方式配置要點(下面均是server1上的配置,server2上的只須要把ip兌換便可)
a. 配置PeerProvider:
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual,rmiUrls=//192.168.2.23:40001/userCache|//192.168.2.23:40001/resourceCache" />
配置中經過手動方式同步sever2中的userCache和resourceCache。
b. 配置CacheManagerPeerListener:
<cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=192.168.2.154, port=40001,socketTimeoutMillis=2000" />
配置中server1監聽本機40001端口。
c. 在每個cache中添加cacheEventListener,例子以下:
<cache name="userCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0"diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,replicateUpdatesViaCopy= false, replicateRemovals= true " /> </cache>
屬性解釋:
必須屬性:
name:設置緩存的名稱,用於標誌緩存,唯一
maxElementsInMemory:在內存中最大的對象數量
maxElementsOnDisk:在DiskStore中的最大對象數量,如爲0,則沒有限制
eternal:設置元素是否永久的,若是爲永久,則timeout忽略
overflowToDisk:是否當memory中的數量達到限制後,保存到Disk
可選的屬性:
timeToIdleSeconds:設置元素過時前的空閒時間
timeToLiveSeconds:設置元素過時前的活動時間
diskPersistent:是否disk store在虛擬機啓動時持久化。默認爲false
diskExpiryThreadIntervalSeconds:運行disk終結線程的時間,默認爲120秒
memoryStoreEvictionPolicy:策略關於Eviction
緩存子元素:
cacheEventListenerFactory:註冊相應的的緩存監聽類,用於處理緩存事件,如put,remove,update,和expire
bootstrapCacheLoaderFactory:指定相應的BootstrapCacheLoader,用於在初始化緩存,以及自動設置。
參考另一篇學習筆記http://wozailongyou.javaeye.com/blog/230252,也有集羣的說明
ehcache 1.5.0以後版本支持的一種方式,配置起來比較簡單,要點:
a. 配置PeerProvider,使用tcp的方式,例子以下:
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" properties="connect=TCP(start_port=7800): TCPPING(initial_hosts=192.168.2.154[7800],192.168.2.23[7800];port_range=10;timeout=3000; num_initial_members=3;up_thread=true;down_thread=true): VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false): pbcast.NAKACK(down_thread=true;up_thread=true;gc_lag=100;retransmit_timeout=3000): pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false; print_local_addr=false;down_thread=true;up_thread=true)" propertySeparator="::" />
b.爲每一個cache添加cacheEventListener:
<cache name="userCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true"/> </cache>
JGroup方式配置的兩個server上的配置文件同樣,如有多個server,在initial_hosts中將server ip加上便可。
一個完整的ehcache.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.sf.net/ehcache.xsd"> <diskStore path="java.io.tmpdir" /> <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory" properties="connect=TCP(start_port=7800): TCPPING(initial_hosts=192.168.2.154[7800],192.168.2.23[7800];port_range=10;timeout=3000; num_initial_members=3;up_thread=true;down_thread=true): VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false): pbcast.NAKACK(down_thread=true;up_thread=true;gc_lag=100;retransmit_timeout=3000): pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false; print_local_addr=false;down_thread=true;up_thread=true)" propertySeparator="::" /> <defaultCache maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true"/> </defaultCache> <cache name="velcroCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true"/> </cache> <cache name="userCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true"/> </cache> <cache name="resourceCache" maxElementsInMemory="10000" eternal="true" overflowToDisk="true" timeToIdleSeconds="0" timeToLiveSeconds="0" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true"/> </cache> </ehcache>