今天在這里了記錄一下學習ehcache分布式集群的過程。
ehcache的三種最為常用集群方式,分別是 RMI、JGroups 以及 EhCache Server 。
這里主要講一下rmi方式。
1、添加依賴
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.3</version>
</dependency>
2、配置文件
spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 自動掃描注解的bean -->
<context:component-scan base-package="com.yitop.feng" />
<!-- 啟用緩存注解功能(請將其配置在Spring主配置文件中) -->
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"></property>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
</beans>
server1的ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<!--
配置提供者
1、peerDiscovery,提供者方式,有兩種方式:自動發現(automatic)、手動配置(manual)
2、rmiUrls,手動方式時提供者的地址,多個的話用|隔開
-->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,rmiUrls=//192.168.30.51:40002/cachetest"
/>
<!--
配置監聽器
1、hostName 主機地址
2、port 端口
3、socketTimeoutMillis socket子模塊的超時時間,默認是2000ms
-->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=192.168.30.51, port=40001, socketTimeoutMillis=2000"
/>
<!-- 默認緩存 -->
<defaultCache
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<!-- cachetest緩存 緩存時間為5秒 -->
<cache name="cachetest"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="300"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU">
<!--
配置緩存事件監聽器
replicateAsynchronously 操作是否異步,默認值為true.
replicatePuts 添加操作是否同步到集群內的其他緩存,默認為true.
replicateUpdates 更新操作是否同步到集群內的其他緩存,默認為true.
replicateUpdatesViaCopy 更新之后的對象是否復制到集群中的其他緩存(true);
replicateRemovals 刪除操作是否同步到集群內的其他緩存,默認為true.
-->
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="
replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true "/>
<!-- 初始化緩存,以及自動設置-->
<bootstrapCacheLoaderFactory class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
</ehcache>
server2的ehcache.xml只要把提供者和監聽者的端口調換就可以了
3、測試
這里是隨便寫個查詢和寫入緩存的方法
@CachePut(value = "cachetest", key = "#key")
public String put(String key, String value) {
System.out.println("保存數據, " + key + " : " + value);
return value;
}
@Cacheable(value = "cachetest", key = "#name")
public String getName(String name) {
return String.valueOf(System.currentTimeMillis());
}
下面是兩個測試類,模擬兩台服務器
test1
package com.yitop.feng;
import com.yitop.feng.service.EhcacheTestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Scanner;
/**
* @author fengzp
* @date 17/3/1下午2:19
* @email fengzp@gzyitop.com
* @company 廣州易站通計算機科技有限公司
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml"})
public class EhcacheTest {
@Autowired
private EhcacheTestService ehcacheTestService;
@Test
public void test() throws InterruptedException {
String name = "feng";
int i = 1;
while (true){
String o = ehcacheTestService.getName(name + i);
System.out.println(i + " : " + o);
i++;
Thread.sleep(1000);
if(i > 5) i = 1;
}
}
}
test2:
package com.yitop.feng;
import com.yitop.feng.service.EhcacheTestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Scanner;
/**
* @author fengzp
* @date 17/3/1下午2:19
* @email fengzp@gzyitop.com
* @company 廣州易站通計算機科技有限公司
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test2/spring2.xml"})
public class EhcacheTest2 {
@Autowired
private EhcacheTestService ehcacheTestService;
@Test
public void test() throws InterruptedException {
String name = "feng";
int i = 1;
while (true){
String o = ehcacheTestService.getName(name + i);
System.out.println(i + " : " + o);
i++;
if(i > 5){
i = 1;
break;
}
}
Thread.sleep(5000);
while (true) {
ehcacheTestService.put(name + i, i++ + "");
if(i > 5) break;
}
while (true){
}
}
}
4、結果
這里先啟動test1,等它把數據都寫到緩存后,啟動test2。可以看到test2啟動后能夠讀取到test1的緩存, 並且之后test2更新緩存后,test1也能同時更新,說明緩存已經成功集群到兩邊。