이제 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 원본이 저장되어 있는지를 설명한다. 다음 단계에서는 분산에 대해 어떻게 제어할 있는지에 대해서 설명할 것이다.

이전 단계에서 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 대해서 살펴볼 것이다.

이번 단계에서는 강력한 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 추가할 것이다.

이전 단계에서 우리는 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 변경했다.

일반적으로 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 대한 설정으로 처리할 있다. 이것은 다음 단계에서 설명할 것이다.