'Infinispan'에 해당되는 글 14건
09. Step-7. Listen to changes in the cache :: 2015/04/08 13:07
이제 cluster topology의 변화에 대해서 어떻게 처리할 수 있는지 알게 되었다. 마찬가지로 cluster 내의 data 변화에 대해서도 처리할 수 있다. 이것이 어떻게 동작하는지 더 잘 보여주기 위해서 2개의 node의 역할을 분리할 것이다. Coordinator에 data를 put하고, 다른 node에서는 cache의 변화된 내용을 보여줄 것이다.
@Listener(clustered = true)
public class CacheListener {
@CacheEntryCreated
public void entryCreated(CacheEntryCreatedEvent<String, LocationWeather> event) {
if (!event.isOriginLocal()) {
System.out.printf("-- Entry for %s modified by another node in the cluster\n", event.getKey());
}
}
}
일반적으로 cache listener는 단지 "local events"에 대해서만 listen할 수 있다. 예를 들어, 동일 node에서 발생한 event에 대해서만 listen 가능하다. 그러나, 이번 예제에서처럼 모든 node에서 발생한 event를 listen하고 싶다면 "clustered = true" annotation parameter를 사용하여 모든 node의 event를 listen할 수 있다.
Event notification을 살펴보자.
git checkout -f step-7
mvn clean package exec:exec # from terminal 1
mvn exec:exec # from terminal 2
[Coordinator Output : PUT]
---- View changed: [hoth-1712]
----
---- Waiting for cluster to form ----
---- View changed: [hoth-1712, hoth-9822] ----
---- Fetching weather information ----
-- Entry for Rome, Italy modified by another node in the cluster
Rome, Italy - Temperature: 11.6° C, Conditions: Sky is Clear
Como, Italy - Temperature: 5.6° C, Conditions: Sky is Clear
-- Entry for Basel, Switzerland modified by another node in the
cluster
Basel, Switzerland - Temperature: 2.9° C, Conditions: broken clouds
Bern, Switzerland - Temperature: -2.1° C, Conditions: scattered clouds
-- Entry for London, UK modified by another node in the cluster
London, UK - Temperature: 4.8° C, Conditions: light rain
-- Entry for Newcastle, UK modified by another node in the
cluster
Newcastle, UK - Temperature: 1.8° C, Conditions: Sky is Clear
-- Entry for Bucharest, Romania modified by another node in the
cluster
Bucharest, Romania - Temperature: 8.4° C, Conditions: few clouds
Cluj-Napoca, Romania - Temperature: 5.8° C, Conditions: broken clouds
-- Entry for Ottawa, Canada modified by another node in the
cluster
Ottawa, Canada - Temperature: -12.3° C, Conditions: overcast clouds
-- Entry for Toronto, Canada modified by another node in the
cluster
Toronto, Canada - Temperature: -10.1° C, Conditions: few clouds
Lisbon, Portugal - Temperature: 15.0° C, Conditions: light rain
-- Entry for Porto, Portugal modified by another node in the cluster
Porto, Portugal - Temperature: 12.1° C, Conditions: moderate rain
Raleigh, USA - Temperature: 6.0° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.5° C, Conditions: light rain
---- Fetched in 5466ms ----
---- Fetching weather information ----
Rome, Italy - Temperature: 11.6° C, Conditions: Sky is Clear
Como, Italy - Temperature: 5.6° C, Conditions: Sky is Clear
Basel, Switzerland - Temperature: 2.9° C, Conditions: broken clouds
Bern, Switzerland - Temperature: -2.1° C, Conditions: scattered
clouds
London, UK - Temperature: 4.8° C, Conditions: light rain
Newcastle, UK - Temperature: 1.8° C, Conditions: Sky is Clear
Bucharest, Romania - Temperature: 8.4° C, Conditions: few clouds
Cluj-Napoca, Romania - Temperature: 5.8° C, Conditions: broken
clouds
Ottawa, Canada - Temperature: -12.3° C, Conditions: overcast
clouds
Toronto, Canada - Temperature: -10.1° C, Conditions: few clouds
Lisbon, Portugal - Temperature: 15.0° C, Conditions: light rain
Porto, Portugal - Temperature: 12.1° C, Conditions: moderate rain
Raleigh, USA - Temperature: 6.0° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.5° C, Conditions: light rain
---- Fetched in 2ms ----
---- Fetching weather information ----
-- Entry for Rome, Italy modified by another node in the cluster
Rome, Italy - Temperature: 11.6° C, Conditions: Sky is Clear
Como, Italy - Temperature: 5.6° C, Conditions: Sky is Clear
-- Entry for Basel, Switzerland modified by another node in the
cluster
Basel, Switzerland - Temperature: 2.9° C, Conditions: broken clouds
Bern, Switzerland - Temperature: -2.1° C, Conditions: scattered clouds
-- Entry for London, UK modified by another node in the cluster
London, UK - Temperature: 4.8° C, Conditions: light rain
-- Entry for Newcastle, UK modified by another node in the
cluster
Newcastle, UK - Temperature: 1.8° C, Conditions: Sky is Clear
-- Entry for Bucharest, Romania modified by another node in the
cluster
Bucharest, Romania - Temperature: 8.4° C, Conditions: few
clouds
Cluj-Napoca, Romania - Temperature: 5.8° C, Conditions: broken clouds
-- Entry for Ottawa, Canada modified by another node in the
cluster
Ottawa, Canada - Temperature: -12.3° C, Conditions: overcast clouds
-- Entry for Toronto, Canada modified by another node in the
cluster
Toronto, Canada - Temperature: -10.1° C, Conditions: few clouds
Lisbon, Portugal - Temperature: 15.0° C, Conditions: light rain
-- Entry for Porto, Portugal modified by another node in the
cluster
Porto, Portugal - Temperature: 12.1° C, Conditions: moderate rain
Raleigh, USA - Temperature: 6.0° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.5° C, Conditions: light rain
---- Fetched in 1248ms ----
[Other Output : Event View]
---- View changed: [hoth-1712,
hoth-9822] ----
---- Waiting for cluster to form ----
-- Entry for Rome, Italy modified by another node in the cluster
-- Entry for Como, Italy modified by another node in the cluster
-- Entry for Basel, Switzerland modified by another node in the cluster
-- Entry for Bern, Switzerland modified by another node in the cluster
-- Entry for London, UK modified by another node in the cluster
-- Entry for Newcastle, UK modified by another node in the cluster
-- Entry for Bucharest, Romania modified by another node in the cluster
-- Entry for Cluj-Napoca, Romania modified by another node in the
cluster
-- Entry for Ottawa, Canada modified by another node in the cluster
-- Entry for Toronto, Canada modified by another node in the cluster
-- Entry for Lisbon, Portugal modified by another node in the cluster
-- Entry for Porto, Portugal modified by another node in the cluster
-- Entry for Raleigh, USA modified by another node in the cluster
-- Entry for Washington, USA modified by another node in the cluster
-- Entry for Rome, Italy modified by another node in the cluster
-- Entry for Como, Italy modified by another node in the cluster
-- Entry for Basel, Switzerland modified by another node in the cluster
-- Entry for Bern, Switzerland modified by another node in the cluster
-- Entry for London, UK modified by another node in the cluster
-- Entry for Newcastle, UK modified by another node in the cluster
-- Entry for Bucharest, Romania modified by another node in the cluster
-- Entry for Cluj-Napoca, Romania modified by another node in the
cluster
-- Entry for Ottawa, Canada modified by another node in the cluster
-- Entry for Toronto, Canada modified by another node in the cluster
-- Entry for Lisbon, Portugal modified by another node in the cluster
-- Entry for Porto, Portugal modified by another node in the cluster
-- Entry for Raleigh, USA modified by another node in the cluster
-- Entry for Washington, USA modified by another node in the cluster
---- View changed: [hoth-9822] ----
실제로 cache에 작업을 수행하는 coordinator에서 남기는 event log와 another node에서 entrries가 수정되었음을 알리는 event log를 볼 수 있을 것이다. 이것은 consistent hashing algorithm에 의해서 entry가 어느 node에 원본이 저장되어 있는지를 설명한다. 다음 단계에서는 분산에 대해 어떻게 제어할 수 있는지에 대해서 설명할 것이다.
08. Step-6. Listen to changes in the cluster :: 2015/04/08 12:52
이전 단계에서 2개의 node에서 cluster를 성공적으로 시작했다. 하지만, cluster에 대한 lifecycle과 2개의 node가 동일한 operation을 효과적으로 수행하도록 거의 제어하지 못했다. 이번 단계에서는 cluster events들에 대해서 들여다보고, cluster topology가 변경될 때, cluster events들이 예상대로 발생한 것인지를 어떻게 확신할 수 있도록 돕는지 알아볼 것이다. 특정 events를 listen하기 위하여 listener를 생성하여 CacheManager에 추가해야 한다. Infinispan listener는 간단하게 @Listener annotation으로 구현할 수 있다. 알고 싶은 events에 대해서 annotation을 추가하면 notify를 받을 수 있다. 예를 들면 다음과 같다.
@Listener
public class ClusterListener {
@ViewChanged
public void viewChanged(ViewChangedEvent event) {
}
}
위의 예제에서는 cluster에 node가 참여하거나 나갈 때마다 notify를 받을 것이다. Event object는 이전 topology에 대한 상세한 정보와 새로운 topology에 대한 상세 정보를 담고 있다. 우리의 WeatherApp에서는 2개의 CountdownLatch Instance와 함께 topology 정보를 사용할 것이다. 하나는 초기 cluster를 구성하는 node의 개수가 될 때까지 기다리고, 다른 하나는 원래의 coordinator node가 cluster를 나갔을 때, node shutdown하도록 허용한다.
git checkout -f step-6
mvn clean package exec:exec # from terminal 1
mvn exec:exec # from terminal 2
이번에는 첫번째 시작한 노드는 job을 수행하기 전에 두번째 node가 cluster에 참여하기까지 기다릴 것이다. 다음 단계에서는 또다른 형태의 event인 Cache Events에 대해서 살펴볼 것이다.
07. Step-5. Clustering the application :: 2015/04/08 12:51
이번 단계에서는 강력한 infinispan의 clustering에 대해 알아볼 것이다. Multiple node간 데이터를 어떻게 공유할 수 있는지를 보여줄 것이다. 이 multiple node는 동일 physical host에 있을 수도 있고, 분리된 VM이나 따로 떨어진 machine에 있을 수도 있다. 이 tutorial의 목적에 맞도록 동일한 host에서 모든 node를 실행하는 것은 network이나 firewall에 대한 변경작업이 필요 없이 때문에 가장 쉬운 방법이다. 최고의 결과를 위해 vertical splitting (여러 개의 터미널 윈도우 사용)을 지원하는 terminal을 사용하라. (Linux : Terminator, OSX : iTerm2, Windows : ConEmu)
CacheManager를 Cluster에 속하도록 설정하기 위하여 특별히 전송이 가능한 "global" configuration을 설정해야 한다.
GlobalConfigurationBuilder global = GlobalConfigurationBuilder.defaultClusteredBuilder(); global.transport().clusterName("WeatherApp");
cacheManager = new DefaultCacheManager(global.build(), config.build());
우리는 편리한 defaultClusterBuilder() method를 사용하여 쉽게 갔지만, GlobalConfigurationBuilder를 구성하고 필요한 파라미터들을 수정함으로 동일한 결과를 얻을 수 있다. Clustered CacheManager를 만드는 것만으로는 충분하지 않다. 우리는 Clustered Cache를 원한다. 이 예제에서는 default cache configuration을 수정하여 기본적으로 2곳에 데이터를 저장하는 distributed synchronous cache를 사용할 것이다.
config.clustering().cacheMode(CacheMode.DIST_SYNC);
우리가 저장한 Entries들은 network을 통해 node간 전송되어야 하기 때문에, key와 value에 대해서 java.io.Serializable interface를 통해 구현할 필요가 있다. Entry들은 key를 hash하여 cluster member들 사이에 분산처리 된다. 2곳에 저장하도록 설정했기 때문에, 각 entry는 primary owner와 backup owner를 가질 것이다. 이제 여러 개의 terminal을 띄워 놓고 다음과 같이 해보자.
git checkout -f step-5
mvn clean package exec:exec # from terminal 1
mvn exec:exec # from terminal 2
서로간에 "wait"하도록 설정하지 않았기 때문에 첫번째 instance가 시작되자마자 두번째 instance를 시작하라. 최종 결과는 이전 단계와 유사하겠지만 (2곳에서 보여짐), 서로 간의 node discovery와 관련된 추가적인 logging을 볼 수 있을 것이다. 우리는 이런 동작을 통제하기 위해서 다음 단계에서는 listener를 추가할 것이다.
06. Step-4. Configuring the default cache :: 2015/04/06 07:13
이전 단계에서 우리는 put() method에 대한 overload로 mortal entries (생명주기를 갖는 데이터)를 저장했다. 하지만, 모든 데이터에 대해서 같은 lifespan으로 유효기간을 설정하고 싶다면, Cache가 default expiration value를 가지도록 설정할 수 있다. 이렇게 하기 위해서 org.infinispan.configuration.cache.Configuration object를 파라미터로 넘겨서 DefaultCacheManager를 구성할 것이다. Infinispan의 Configuration은 대부분 runtime시에는 변경할 수 없다. 그리고 ConfigurationBuilder를 통해서 생성할 수 있다. 위의 use-case (ConfigurationBuilder를 이용)의 경우, 모든 entries에 대해 5초간의 기본 유효기간을 가지도록 cache configuration을 생성해보자. 다음 코드는 어떻게 생성할 수 있는지를 보여준다.
ConfigurationBuilder config = new ConfigurationBuilder();
config.expiration().lifespan(5, TimeUnit.SECONDS);
cacheManager = new DefaultCacheManager(config.build());
Configuration Builder는 fluent pattern (method cascading or method chaning)을 사용한다. 따라서 chained method를 통해서 configuration을 튜닝할 수 있다. 다시 application을 실행해보자.
git checkout -f step-4
mvn clean package exec:exec
이전 단계와 같은 결과가 나올 것이다. 우리는 application의 동작을 변경한 것이 아니라 cache에 대한 semantics만 변경했다.
05. Step-3. Making Entries expire :: 2015/04/06 07:12
일반적으로 application은 값비싼 계산 결과나 data를 조회하는 것이 data-source를 더 느리게 하는 경우 (ex. Database or webservice) cache data로 저장한다. 만약 그러한 데이터가 도시명이나 제품 형태와 같이 변경할 수 없다면 (혹은 대부분 변경할 수 없는 경우) 그러한 형태로 저장하는 경우는 의미가 있다. 하지만, 데이터가 주기적으로 재생성되거나 다시 조회해야 할 필요가 있다면 expiration time (유효기간)을 설정하는 것을 고려해볼 만하다. 이런 cache entry들을 mortal (생명주기를 갖는 데이터)이라고 한다. Infinispan에서는 2가지 형태로 entry expiration time을 설정할 수 있다.
- 데이터가 cache에 저장된 이후 유효 기간 (ex. lifespan)
- 데이터의 최종 접근 시간 (last accessed time)이후 유효 기간 (ex. Maximum idle time)
Cache Interface는 특별히 하나 혹은 두가지 expiration properties들을 적용할 수 있도록 put() method의 overloaded version을 제공한다. 다음 예제는 5초간의 유효기간을 갖는 entry를 어떻게 저장하는 지를 보여준다.
cache.put(location, weather, 5, TimeUnit.SECONDS);
이것을 유념하면서
application을 다시 실행시켜 보자.
git checkout -f step-3
mvn clean package exec:exec
[Output]
---- Fetching weather
information ----
Rome, Italy - Temperature: 12.9° C, Conditions: light rain
Como, Italy - Temperature: 6.3° C, Conditions: Sky is Clear
Basel, Switzerland - Temperature: 0.8° C, Conditions: overcast
clouds
Bern, Switzerland - Temperature: -1.6° C, Conditions: broken
clouds
London, UK - Temperature: 1.8° C, Conditions: light rain
Newcastle, UK - Temperature: 2.6° C, Conditions: scattered
clouds
Bucharest, Romania - Temperature: 9.3° C, Conditions: scattered
clouds
Cluj-Napoca, Romania - Temperature: 6.4° C, Conditions: scattered
clouds
Ottawa, Canada - Temperature: -7.0° C, Conditions: overcast
clouds
Toronto, Canada - Temperature: -7.0° C, Conditions: broken clouds
Lisbon, Portugal - Temperature: 14.6° C, Conditions: overcast
clouds
Porto, Portugal - Temperature: 12.2° C, Conditions: moderate rain
Raleigh, USA - Temperature: 3.9° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.4° C, Conditions: light rain
---- Fetched in 1205ms ----
---- Fetching weather information ----
Rome, Italy - Temperature: 12.9° C, Conditions: light rain
Como, Italy - Temperature: 6.3° C, Conditions: Sky is Clear
Basel, Switzerland - Temperature: 0.8° C, Conditions: overcast
clouds
Bern, Switzerland - Temperature: -1.6° C, Conditions: broken
clouds
London, UK - Temperature: 1.8° C, Conditions: light rain
Newcastle, UK - Temperature: 2.6° C, Conditions: scattered clouds
Bucharest, Romania - Temperature: 9.3° C, Conditions: scattered
clouds
Cluj-Napoca, Romania - Temperature: 6.4° C, Conditions: scattered
clouds
Ottawa, Canada - Temperature: -7.0° C, Conditions: overcast
clouds
Toronto, Canada - Temperature: -7.0° C, Conditions: broken clouds
Lisbon, Portugal - Temperature: 14.6° C, Conditions: overcast
clouds
Porto, Portugal - Temperature: 12.2° C, Conditions: moderate rain
Raleigh, USA - Temperature: 3.9° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.4° C, Conditions: light rain
---- Fetched in 2ms ----
---- Fetching weather information ----
Rome, Italy - Temperature: 12.9° C, Conditions: light rain
Como, Italy - Temperature: 6.3° C, Conditions: Sky is Clear
Basel, Switzerland - Temperature: 0.8° C, Conditions: overcast
clouds
Bern, Switzerland - Temperature: -1.6° C, Conditions: broken
clouds
London, UK - Temperature: 1.8° C, Conditions: light rain
Newcastle, UK - Temperature: 2.6° C, Conditions: scattered
clouds
Bucharest, Romania - Temperature: 9.3° C, Conditions: scattered
clouds
Cluj-Napoca, Romania - Temperature: 6.4° C, Conditions: scattered
clouds
Ottawa, Canada - Temperature: -7.0° C, Conditions: overcast clouds
Toronto, Canada - Temperature: -7.0° C, Conditions: broken clouds
Lisbon, Portugal - Temperature: 14.6° C, Conditions: overcast
clouds
Porto, Portugal - Temperature: 12.2° C, Conditions: moderate rain
Raleigh, USA - Temperature: 3.9° C, Conditions: Sky is Clear
Washington, USA - Temperature: 3.4° C, Conditions: light rain
---- Fetched in 1048ms ----
Expiration이 어떻게 동적하는지를 보여주기 위해서 우리는 5초간의 sleep time을 추가하고, 세번째로 각 도시의 날씨를 조회하여 출력해 보았다. 위에서 보는 것처럼 세번째 조회 작업 수행 시간은 거의 첫번째 경우 (uncached case)와 비슷하게 측정되는 것을 볼 수 있다 : 모든 entries들이 유효기간이 지났다. Infinispan에서 expiration은 느슨하게 확인한다. 예를 들어, 유효기간이 지난 entry를 조회하려고 시도할 경우, 그 시점에 해당 entry는 cache에서 삭제될 것이다. Eviction을 사용하여 pro-active removal (선제적으로 삭제)도 가능하다.
기본적으로 cache의 모든 entry에 대해서 expire되기를 원하는 경우에는 특별히 put() method 호출을 사용할 필요 없이 cache에 대한 설정으로 처리할 수 있다. 이것은 다음 단계에서 설명할 것이다.