ehcache 實現快取共享
公司專案最近在做快取同步的工作,研發組搞了一套zookeeper的外掛,快取存放在ehcache中,因為要依賴第三方外掛,感覺很麻煩,ehcache本身就支援快取同步且方式比較多。
如下樣例簡單實現兩個應用之間的ehcache快取共享(RMI),同步更新。
同步執行兩個Java程式發現跟新快取會同步更新,具體程式碼不做解釋,工程師們執行一把就知真相。
節點一
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="e:\\Data" />
<defaultCache
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
/>
<cache name="a"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
diskPersistent="true"
/>
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//localhost:40002/sampleDistributedCache2"
propertySeparator=","
/>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40001, socketTimeoutMillis=2000"
/>
<cache name="sampleDistributedCache2"
maxElementsInMemory="1000000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicatePutsViaCopy=true, replicateUpdates=true,
replicateUpdatesViaCopy=true, replicateRemovals=true,
asynchronousReplicationIntervalMillis=200"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
</ehcache>
節點二配置檔案 ehcache2.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="e:\\Data" />
<defaultCache
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
/>
<cache name="a"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
diskPersistent="true"
/>
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//localhost:40001/sampleDistributedCache2"
propertySeparator=","
/>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=localhost, port=40002, socketTimeoutMillis=2000"
/>
<cache name="sampleDistributedCache2"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicatePutsViaCopy=true, replicateUpdates=true,
replicateUpdatesViaCopy=true, replicateRemovals=true,
asynchronousReplicationIntervalMillis=200"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
</ehcache>
程式碼部分
節點一程式碼:
package my.test.ehcache;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.management.ManagementService;
public class EHCacheTest {
public static void main(String[] args) {
CacheManager cacheManager = CacheManager.create("src/com/x/ehcache.xml");
//讀入配置
//列印初始快取
String[] cacheNames = cacheManager.getCacheNames();
printNames(cacheNames);
//移除快取
cacheManager.removeCache("sampleDistributedCache1");
cacheNames = cacheManager.getCacheNames();
printNames(cacheNames);
// distributed -- rmi同步
Cache cache = cacheManager.getCache("sampleDistributedCache2");
//註冊被管理的Bean
// JMX -- jconsole(MBeanServer)
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(cacheManager, mBeanServer, true, true,
true, true);
for (int i = 0; i < 100000; i++) {
Element temp = cache.get("ehcache");
System.out.println("cache.getSize()="+cache.getSize());
cache.put(new Element(i, i));
System.out.println("第"+i+"次cache.put");
if (temp != null) {
System.out.println(temp.getValue());
} else {
System.out.println("NotFound");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void printNames(String[] names) {
System.out.println("=======================");
for (int i = 0; i < names.length; i++) {
System.out.println(names[i]);
}
}
}
節點二程式碼:
package my.test.ehcache2;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.Statistics;
import net.sf.ehcache.management.ManagementService;
public class EHCacheTest {
public static void main(String[] args) {
//讀入配置
CacheManager cacheManager = CacheManager.create("src/com/x/ehcache2.xml");
//列印初始快取
String[] cacheNames = cacheManager.getCacheNames();
//註冊管理Bean
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(cacheManager, mBeanServer, true, true, true, true);
//distributed
Cache cache = cacheManager.getCache("sampleDistributedCache2");
//新增值後另一個虛擬機器的快取通過RMI會同步快取,並讀到這個值
cache.put(new Element("ehcache", "newaddvalue"));
printCache(cache);
for (int i = 0; i < 10000; i++) {
try {
Thread.sleep(3000);
System.out.println("第"+i+"次載入cache.size="+cache.getSize());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static void printCache(Cache cache) {
int size = cache.getSize();
long memSize = cache.getMemoryStoreSize();
long diskSize = cache.getDiskStoreSize();
Statistics stat = cache.getStatistics();
long hits = stat.getCacheHits();
StringBuilder sb = new StringBuilder();
sb.append("size=" + size + ";memsize=" + memSize);
sb.append(";diskSize=" + diskSize + ";hits=" + hits);
System.out.println(sb.toString());
}
}