티스토리 뷰
앞서 다음과 같이 EhCache를 사용하는 방법과 설정하는 방법에 대해 살펴보았다.
이번에 다룰 내용은 EhCache를 이용해 분산캐시(Cache Clustering)를 하는 방법에 대해 알아보겠다.
분산캐시의 목적은 어플리케이션이 여러개의 노드에 올라가있는 상황에서 한 노드의 캐시에 변화가 생기면 나머지 노드에 그 변경 내용을 전달하여 같은 상태로 유지하는 것이다.
각 노드간 캐시 데이터 전송은 자바에서 기본적으로 제공하는 원격 메커니즘인 RMI를 통해 이루어진다.
RMI를 하기 위해서는 노드를 발견해야 하는데 이 글에서는 멀티캐스트 방식을 통해서 다른 노드를 발견하도록 하였다.
멀티캐스트 방식은 지정한 멀티캐스트 IP(224.0.0.1~239.255.255.255)와 포트에 참여하는 노드를 자동으로 발견하는 것으로써 지정한 IP와 Port에 참여한 노드는 자기 자신을 다른 노드에 통지하므로 클러스터에 동적으로 노드를 추가하거나 제거살 수 있다.
이것을 어떤 방식으로 설정하고 사용하는지 살펴보도록 하자.
분산캐시 설정
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import net.sf.ehcache.Cache;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.CacheConfiguration.CacheEventListenerFactoryConfiguration;
import net.sf.ehcache.config.CacheConfiguration.TransactionalMode;
import net.sf.ehcache.config.DiskStoreConfiguration;
import net.sf.ehcache.config.FactoryConfiguration;
import net.sf.ehcache.config.PersistenceConfiguration;
@EnableCaching
@Configuration
public class CacheConfig {
private net.sf.ehcache.CacheManager createCacheManager() {
net.sf.ehcache.config.Configuration configuration = new net.sf.ehcache.config.Configuration();
configuration.diskStore(new DiskStoreConfiguration().path("java.io.tmpdir"));
// Cluster 설정
this.setClusterConfig(configuration);
return net.sf.ehcache.CacheManager.create(configuration);
}
// Cluster 설정
private void setClusterConfig(net.sf.ehcache.config.Configuration configuration) {
// multicast 설정
FactoryConfiguration factoryConfig = new FactoryConfiguration()
.className("net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory")
.properties("peerDiscovery=automatic,multicastGroupAddress=230.0.0.1,multicastGroupPort=44444,timeToLive=32")
.propertySeparator(",");
// 다른 노드에서 발생한 이벤트 리스너
FactoryConfiguration listenerFactoryConfig = new FactoryConfiguration()
.className("net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory")
.properties("socketTimeoutMillis=2000")
.propertySeparator(",");
configuration.addCacheManagerPeerProviderFactory(factoryConfig);
configuration.addCacheManagerPeerListenerFactory(listenerFactoryConfig);
}
@Bean
public EhCacheCacheManager ehCacheCacheManager() {
net.sf.ehcache.CacheManager manager = this.createCacheManager();
// 캐시 별 변경 내역을 전송 설정
CacheEventListenerFactoryConfiguration eventListenerFactoryConfig = new CacheEventListenerFactoryConfiguration()
.className("net.sf.ehcache.distribution.RMICacheReplicatorFactory")
.properties("replicateAsynchronously=true,replicatePuts=false,replicateUpdates=true,replicateUpdatesViaCopy=false,replicateRemovals=true")
.propertySeparator(",");
Cache getMenuCache = new Cache(new CacheConfiguration()
.maxEntriesLocalHeap(1000)
.maxEntriesLocalDisk(10000)
.eternal(false)
.timeToIdleSeconds(1800)
.timeToLiveSeconds(1800)
.memoryStoreEvictionPolicy("LRU")
.transactionalMode(TransactionalMode.OFF)
.persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.LOCALTEMPSWAP))
.name("getMenu")
.cacheEventListenerFactory(eventListenerFactoryConfig) // Cluster 설정
);
manager.addCache(getMenuCache);
return new EhCacheCacheManager(manager);
}
}
기본적인 캐시 설정에서 주석으로 명시한 부분이 분산 캐시를 위해 추가된 부분이라고 보면 된다.
23 line : CacheManager에 Cluster 설정을 넣는다. 분산 캐시를 하지 않으려면 이 부분만 주석처리하면 된다.
31 line : 멀티캐스트 설정을 하는 부분이다. (RMICacheManagerPeerProviderFactory)
property | desc |
peerDiscovery | automatic = 멀티캐스트 방식 |
multicastGroupAddress | 멀티캐스트 IP |
multicastGroupPort | 포트 번호 |
37 line : 다른 노드에서 발생한 이벤트에 대한 리스너 설정을 하는 부분이다. (RMICacheManagerPeerListenerFactory)
property | desc |
port | 메시지를 수신할 때 사용되는 포트 |
socketTimeoutMillis | 이 노드에 메시지를 보냈을 때 메시지 전송을 기다리는 시간. 기본값은 2000ms. |
52 line : 캐시별 변경내용에 대한 전송 설정 부분이다. (RMICacheReplicatorFactory)
property | desc | default value |
replicatePuts | 캐시에 새로운 요소가 추가됐을 때 다른 노드에 복사할지의 여부 | true |
replicateUpdates | 캐시 요소의 값이 변경되었을 때 다른 노드에 값을 복사할지의 여부 | true |
replicateRemovals | 캐시 요소가 삭제되었을 때 다른 노드에 반영할지의 여부 | true |
replicateAsynchronously | 비동기로 값을 복사할지의 여부 | true |
replicateUpdatesViaCopy | 새로운 요소를 다른 노드에 복사할지 아니면 삭제 메시지를 보낼지의 여부 | true |
asynchronousReplicationIntervalMillis | 비동기 방식을 사용할 때 변경 내역을 다른 노드에 통지하는 주기 | 1000 |
즉 분산 캐시를 하기 위해서는 RMICacheManagerPeerProviderFactory, RMICacheManagerPeerListenerFactory, RMICacheReplicatorFactory 에 대한 설정이 필요하다.
이렇게 설정을 하고 각각 다른 서버에서 동일한 어플리케이션을 기동해보자. EhCache 관련 설정들이 쭉 로딩되는것이 보이고 다 기동이 되면 다른 서버에 올라간 어플리케이션과 연결된것을 확인할 수 있다.
[13:37:35.990][DEBUG][net.sf.ehcache.distribution.MulticastKeepaliveHeartbeatReceiver.processPayload:line148] - rmiUrls received //xxx.xxx.xxx.xxx:55755/getMenu
[13:37:35.990][DEBUG][net.sf.ehcache.distribution.RMICacheManagerPeerProvider.lookupRemoteCachePeer:line126] - Lookup URL //xxx.xxx.xxx.xxx:55755/getMenu
끝!
'Lang > Java' 카테고리의 다른 글
JAVA 실행시 Picked up JAVA_TOOL_OPTIONS 뜻, 그리고 설정방법 (1) | 2021.10.18 |
---|---|
An illegal reflective access operation has occurred 오류 조치 (0) | 2021.09.30 |
EhCache xml config를 java config로 변환하기 (0) | 2021.08.31 |
ModelMapper를 이용해 DTO와 Entity Converting 하기 (0) | 2021.06.18 |
JAVA Base64 Encoding Decoding 예제 (0) | 2021.06.03 |