분산캐시로 JBoss 에서 제작한 Infinispan 은 메모리 캐시로만 알고 있었는데, 여러가지 Cache Store 를 이미 제공하고 있더군요. 특히 Lucene 용이라던지, Jdbc 라던지...
Infinispan 5.3 부터는 MongoDB 를 캐시 저장소로 사용이 가능하더군요. 캐시 중에 영구 저장소에 저장해야 할 경우이면서, 빠른 PUT 성능이 필요로 하는 곳에 쓰면 좋을 것 같습니다.
우선 저는 Infinispan을 Hibernate 2nd cache 로 사용하기도 하는데요, RDBMS 보다야 캐시가 빠르지만, 보통은 휘발성이라 중간 접점이 있으면 좋겠다 싶었는데, Infinispan이 저장소로 NoSQL 을 사용할 수 있다면, 더 좋겠다 싶더군요.
제가 보통 이런 것의 사용처로는 통계성 데이터의 백데이터를 하루나 일주일 정도 캐시에 남겨 놓는 것입니다. 메모리가 제한적이니, NoSQL 에 저장했다가 거기서 로드해서 사용하고, RDBMS 는 처음 읽기만 하고 더 이상 접근하지 않는다면 좋겠다 싶어서지요.
그럼 Infinispan 과 MongoDB 를 활용해서 캐시를 사용해 보도록 하겠습니다.
우선 infinispan-core, infinispan-cachestore-mongodb 를 maven dependency 에 추가합니다. 현재 가장
최신 버전은 5.3.0.Final 입니다.
코드는 Infinispan을 사용하는 것과 같고, 다만 CacheStore를 설정해주는 부분만 새로 추가하면 됩니다.
여기서는 ConfigurationBuilder 를 이용하여 MongoDB CacheStore 설정을 수행했습니다.
MongoDbAsCaceStoreTest.java
보안을 위해서 username, password 도 설정이 가능합니다.
좀 더 자세한 내용은 Infinispan CacheStore 를 참고하세요.
참 MongoDB 에 접속하기 위해 Java 용 Driver 도 dependency에 추가해 주세요.
2013년 7월 20일 토요일
2013년 3월 26일 화요일
Spring 3.1 + Redis 를 이용한 Cache
이번 주에는 Spring 3.1 에서 지원하는 Cache 관련해서 많은 글을 썼는데, 요즘 가장 많이 사용되는 Redis 를 저장소로 사용하는 Cache 를 만들겠습니다.
Redis 를 구현하기 위해서 spring-data-redis 와 jedis 라이브러리를 사용했습니다.
jedis 만으로도 구현할 수 있지만, 편하게 spring-data-redis 의 RedisTemplate 를 사용하기로 했습니다.
우선 Redis 를 캐시 저장소로 사용하기 위해 환경설정을 합니다.
1. RedisCacheConfiguration.java
한가지 RedisCacheFactory를 생성할 때 주의할 점은 JedisShardInfo 로 생성해야지, JedisPoolingConfig나 기본 생성자로 생성 시에 RedisTemplate 에서 connection을 제대로 생성 못하는 버그가 있더군요 ㅠ.ㅠ 이 것 때문에 반나절을 허비...
2. RedisCacheManager.java
3. RedisCache.java
RedisCache의 get / put 은 일반적으로 쓰는 opsForValue() 를 사용했습니다. 다른 것을 사용할 수도 있을텐데, 좀 더 공부한 다음에 다른 것으로 변경해 봐야 할 듯 합니다.
마지막에 clear() 메소드도 jedis 에는 flushDB(), flushAll() 메소드를 지원하는데, RedisTemplate에서는 해당 메소드를 expose 하지 않아 코드와 같이 RedisCallback 을 구현했습니다.
4. RedisCacheTest.java
UserRepository는 전에 쓴 Spring 3.1 + EhCache 등의 글과 같은 코드라 생략했습니다.
Redis 관련은 Windows 에서는 구 버전만 지원하고, 신 버전은 linux 만 가능하더군요...
그래도 성능은 정평이 나있으니, HA 구성 시에는 가장 먼저 고려되어야 할 캐시 저장소라 생각됩니다.
저는 앞으로 hibernate 2nd cache provider for redis, hibernate-ogm-redis 를 만들어 볼 예정입니다.
Redis 를 구현하기 위해서 spring-data-redis 와 jedis 라이브러리를 사용했습니다.
jedis 만으로도 구현할 수 있지만, 편하게 spring-data-redis 의 RedisTemplate 를 사용하기로 했습니다.
우선 Redis 를 캐시 저장소로 사용하기 위해 환경설정을 합니다.
1. RedisCacheConfiguration.java
한가지 RedisCacheFactory를 생성할 때 주의할 점은 JedisShardInfo 로 생성해야지, JedisPoolingConfig나 기본 생성자로 생성 시에 RedisTemplate 에서 connection을 제대로 생성 못하는 버그가 있더군요 ㅠ.ㅠ 이 것 때문에 반나절을 허비...
2. RedisCacheManager.java
3. RedisCache.java
RedisCache의 get / put 은 일반적으로 쓰는 opsForValue() 를 사용했습니다. 다른 것을 사용할 수도 있을텐데, 좀 더 공부한 다음에 다른 것으로 변경해 봐야 할 듯 합니다.
마지막에 clear() 메소드도 jedis 에는 flushDB(), flushAll() 메소드를 지원하는데, RedisTemplate에서는 해당 메소드를 expose 하지 않아 코드와 같이 RedisCallback 을 구현했습니다.
4. RedisCacheTest.java
UserRepository는 전에 쓴 Spring 3.1 + EhCache 등의 글과 같은 코드라 생략했습니다.
Redis 관련은 Windows 에서는 구 버전만 지원하고, 신 버전은 linux 만 가능하더군요...
그래도 성능은 정평이 나있으니, HA 구성 시에는 가장 먼저 고려되어야 할 캐시 저장소라 생각됩니다.
저는 앞으로 hibernate 2nd cache provider for redis, hibernate-ogm-redis 를 만들어 볼 예정입니다.
2013년 3월 25일 월요일
Spring 3.1 + Couchbase 를 이용하여 Cache 만들기
오늘 글 쓴 김에 다 써버려야 겠네요...
이번에는 Couchbase 를 저장소로 사용하여, Spring Cache 를 사용해 보도록 하겠습니다.
간략하게 Couchbase 에 대해 설명하면... Memcached + CouchDB 라고 보시면 되구요. 설정에 따라 메모리 저장소로 (Memcached), Document DB 형태(CouchDB) 로 사용할 수 있습니다.
Memcached 의 단순 캐시에서 DocumentDB 로 발전했다고 보시면 되고, Map Reduce 도 가능합니다.
하지만!!! 오늘은 그냥 캐시로 사용하려고 합니다.
1. CouchbaseCacheManager
2. CouchbaseCache
3. CouchbaseCacheConfiguration
환경 설정은 각자 환경에 맞추면 됩니다만, default bucket 만 비밀번호 없이 접근이 가능합니다.
다른 bucket 을 사용하려면, 미리 만드시고, 보안을 설정하셔야 합니다.
4. Couchbase Admin Screenshot
이번에는 Couchbase 를 저장소로 사용하여, Spring Cache 를 사용해 보도록 하겠습니다.
간략하게 Couchbase 에 대해 설명하면... Memcached + CouchDB 라고 보시면 되구요. 설정에 따라 메모리 저장소로 (Memcached), Document DB 형태(CouchDB) 로 사용할 수 있습니다.
Memcached 의 단순 캐시에서 DocumentDB 로 발전했다고 보시면 되고, Map Reduce 도 가능합니다.
하지만!!! 오늘은 그냥 캐시로 사용하려고 합니다.
1. CouchbaseCacheManager
2. CouchbaseCache
3. CouchbaseCacheConfiguration
환경 설정은 각자 환경에 맞추면 됩니다만, default bucket 만 비밀번호 없이 접근이 가능합니다.
다른 bucket 을 사용하려면, 미리 만드시고, 보안을 설정하셔야 합니다.
4. Couchbase Admin Screenshot
이제 남은 건 Redis 만 남았네요... 요건 다음 기회에...
Spring 3.1 + MongoDB 를 이용한 Cache
앞서 EhCache, Memcached 는 일반적으로 메모리를 저장소로 사용합니다만, MongoDB 와 Couchbase 는 정보를 Document 로 관리하는 NoSQL DB라 볼 수 있습니다.
이런 의미로 단순 캐시로 쓰기에는 너무 많은 기능을 가지고 있다고 봐야합니다. 그런만큼 메모리에서만 작동하는 캐시시스템보다는 성능은 느립니다.
하지만 대용량 데이터나 캐시해야 할 양이 엄청 많다면? 그리고 한번 캐시한 거 영구 저장이 되면 좋겠다면? (물론 삭제 기능은 있고...)
에이 그런거라면 차라리 주 저장소를 Document DB로 바꾸는게 낫죠..
아 그렇긴 하네요... 근데, 개발자들이 NoSQL을 아주 단순히 쓰는 큰 이유는 RDBMS 처럼 관계형 데이터 처리에 익숙해서 key-value나 Document, grid 에 대한 처리에 난감해 한다는 거지요. 이 문제는 hibernate-ogm 으로 어떻게 해결하는지 향후 글을 써 보겠습니다.
우선 MongoDB 로도 가능하다는 보여 드리죠.
우선 제가 사용한 라이브러리는 spring-data-mongo, mongo-java-driver 입니다.
1. MongoCacheManager
2. MongoCache
MongoCacheManager 는 별 내용 없구요... MongCache는 Spring 의 MongoTemplate 를 적극 이용하여, 저장/검색을 수행하였습니다.
상세 내용은 Spring Data Mongo 매뉴얼을 보시면 되겠습니다.
3. MongoCacheConfiguration
너무 간단하죠? 나머지 테스트 코드는 앞 EhCache, Memcached 의 예와 똑같아서 생략하겠습니다.
MongoDB의 경우 Database를 지정해주고, 각 캐시명을 Collection 명으로 매핑합니다.
그럼 이만...
이런 의미로 단순 캐시로 쓰기에는 너무 많은 기능을 가지고 있다고 봐야합니다. 그런만큼 메모리에서만 작동하는 캐시시스템보다는 성능은 느립니다.
하지만 대용량 데이터나 캐시해야 할 양이 엄청 많다면? 그리고 한번 캐시한 거 영구 저장이 되면 좋겠다면? (물론 삭제 기능은 있고...)
에이 그런거라면 차라리 주 저장소를 Document DB로 바꾸는게 낫죠..
아 그렇긴 하네요... 근데, 개발자들이 NoSQL을 아주 단순히 쓰는 큰 이유는 RDBMS 처럼 관계형 데이터 처리에 익숙해서 key-value나 Document, grid 에 대한 처리에 난감해 한다는 거지요. 이 문제는 hibernate-ogm 으로 어떻게 해결하는지 향후 글을 써 보겠습니다.
우선 MongoDB 로도 가능하다는 보여 드리죠.
우선 제가 사용한 라이브러리는 spring-data-mongo, mongo-java-driver 입니다.
1. MongoCacheManager
2. MongoCache
MongoCacheManager 는 별 내용 없구요... MongCache는 Spring 의 MongoTemplate 를 적극 이용하여, 저장/검색을 수행하였습니다.
상세 내용은 Spring Data Mongo 매뉴얼을 보시면 되겠습니다.
3. MongoCacheConfiguration
너무 간단하죠? 나머지 테스트 코드는 앞 EhCache, Memcached 의 예와 똑같아서 생략하겠습니다.
MongoDB의 경우 Database를 지정해주고, 각 캐시명을 Collection 명으로 매핑합니다.
그럼 이만...
2012년 12월 6일 목요일
Google Guava 의 LoadingCache 를 이용한 메모리 캐시
Goolge Guava 는 Apache Commons 에서 제공하지 않는 유용한 Utility성 기능들이 상당히 많습니다.
특히 단순한 캐시 시스템의 경우, 캐시 시스템을 데이터 소스와는 별개로 다뤄야 하는 귀찮은 점이 있는데, 아주 간단하지만, 아예 "캐시 시스템 네가 필요할 때 데이터 소스를 직접 조회해서 캐시에 담아 놓으렴", 그럼 난 그냥 그걸 사용할께... 이런 목적에 딱 맞게 제공되는 클래스가 LoadingCache 라는 게 있습니다.
아래 코드는 특정 URL 의 컨텐츠를 메모리 상에서 캐시하고, 제공할 수 있도록 해주는 클래스인데, Google Guava의 LoadingCache를 이용하여 구현하였습니다.
코드를 보시면 아시겠지만, 처음 필요할 때 웹에서 컨텐츠를 다운받고, 그것을 캐시하여 사용하도록 하고 있습니다.
이 코드에서는 Expiry 에 대한 정책은 지정할 수 없게 되어 있지만, 직접 구현하던가, Guava에서 지원하는지 조사해서 지원한다면 그걸 사용하는 게 정신 건강에 좋겠죠^^
이번 글은 java 에서 apache commons 가 기본 중의 기본 라이브러리지만, google guava 도 이제 기본 중에 기본이 될 것입니다.
그 이외에도 아주 많은 유용한 기능이 있으니 공부해 보시기 바랍니다.^^
특히 단순한 캐시 시스템의 경우, 캐시 시스템을 데이터 소스와는 별개로 다뤄야 하는 귀찮은 점이 있는데, 아주 간단하지만, 아예 "캐시 시스템 네가 필요할 때 데이터 소스를 직접 조회해서 캐시에 담아 놓으렴", 그럼 난 그냥 그걸 사용할께... 이런 목적에 딱 맞게 제공되는 클래스가 LoadingCache 라는 게 있습니다.
아래 코드는 특정 URL 의 컨텐츠를 메모리 상에서 캐시하고, 제공할 수 있도록 해주는 클래스인데, Google Guava의 LoadingCache를 이용하여 구현하였습니다.
package kr.kth.commons.caching.repository;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import kr.kth.commons.caching.CacheRepositoryBase;
import kr.kth.commons.tools.StringTool;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.util.EntityUtils;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* Google Guava 의 {@link LoadingCache} 를 이용하여, 캐시 값을 구하는 방법을 미리 지정하여, 쉽게 캐시를 운영할 수 있도록 캐시입니다.
* User: sunghyouk.bae@gmail.com
* Date: 12. 12. 5.
*/
@Slf4j
public class FutureWebCacheRepository extends CacheRepositoryBase {
private final LoadingCache cache;
public FutureWebCacheRepository() {
cache =CacheBuilder.newBuilder().build(getCacheLoader());
}
@Override
public Object get(String key) {
try {
return cache.get(key);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
public void set(String key, Object value, long validFor) {
String str = (value != null) ? value.toString() : "";
cache.put(key, str);
}
@Override
public void remove(String key) {
cache.invalidate(key);
}
@Override
public void removes(String... keys) {
cache.invalidateAll(Arrays.asList(keys));
}
@Override
public boolean exists(String key) {
return cache.getIfPresent(key) != null;
}
@Override
public void clear() {
cache.cleanUp();
}
private static CacheLoader getCacheLoader() {
return
new CacheLoader() {
@Override
public String load(String key) throws Exception {
if (FutureWebCacheRepository.log.isDebugEnabled())
FutureWebCacheRepository.log.debug("URI=[{}] 의 웹 컨텐츠를 비동기 방식으로 다운로드 받아 캐시합니다.", key);
String responseStr = "";
HttpAsyncClient httpClient = new DefaultHttpAsyncClient();
try {
httpClient.start();
HttpGet request = new HttpGet(key);
Future future = httpClient.execute(request, null);
HttpResponse response = future.get();
responseStr = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8"));
if (log.isDebugEnabled())
log.debug("URI=[{}]로부터 웹 컨텐츠를 다운로드 받았습니다. responseStr=[{}]",
key, StringTool.ellipsisChar(responseStr, 255));
} finally {
httpClient.shutdown();
}
return responseStr;
}
};
}
}
코드를 보시면 아시겠지만, 처음 필요할 때 웹에서 컨텐츠를 다운받고, 그것을 캐시하여 사용하도록 하고 있습니다.
이 코드에서는 Expiry 에 대한 정책은 지정할 수 없게 되어 있지만, 직접 구현하던가, Guava에서 지원하는지 조사해서 지원한다면 그걸 사용하는 게 정신 건강에 좋겠죠^^
이번 글은 java 에서 apache commons 가 기본 중의 기본 라이브러리지만, google guava 도 이제 기본 중에 기본이 될 것입니다.
그 이외에도 아주 많은 유용한 기능이 있으니 공부해 보시기 바랍니다.^^
피드 구독하기:
글 (Atom)
.png)