IT/PROGRAMMING

[Java] 일정시간이 지나면 값이 없어지는(expiring) 맵, 캐시로 사용가능한 ExpiringMap

하마연구소장 2019. 2. 24. 19:13
728x90
반응형

자바 프로그래밍을 하다보면 콜렉션(collection) 중에 맵(Map)을 많이 사용하게 된다.

동시성(synchronization) 처리를 위하여 자바는 기본적으로 thread-safe한 java.util.concurrent.ConcurrentMap 객체를 제공한다.
또는 java.util.Collections.synchronizedMap()을 이용해도 된다.

그리고 복합키를 이용할 수 있도록 Apache에서 MultiKeyMap 객체도 제공한다.

Map에 키와 값을 계속해서 put하게되면 key만 중복되지 않으면 자꾸자꾸 들어가게 된다.
그 개수야 상당하게 크지만 그만큼 메모리 사용량은 늘어나게 된다.
필자도 spring-integration에서 이러한 현상을 발견하게 되었고 이를 해결하기 위하여, 일정시간이 지나면 Map에서 자동으로 제거되는 기능이 필요하였다.
물론 제거된 데이터는 더이상 필요없거나 다른 방법으로 다시 복구할 수 있는 상황이었다.
즉, 캐시와 유사한 기능을 가진 Map이 필요했다.
유사한 기능이 아니고, 그냥 캐시다.
캐시의 여러 정책중에 time-based 정책을 적용할 수 있는 Map이다.


ExpiringMap 이라는 라이브러를 찾게되었다.

2019년 2월 24일 기준, 최신버전은 0.5.9 이다.

소개페이지는 GitHub에 있다.


특징은 다음과 같다.

  • High performance: 고성능이란다. 성능 테스트는 안해봤지만, 믿어야지!
  • Low-overhead: Time-based이니깐 시간 계산을 할텐데, 연산이나 메모리 사용량이 많지 않은가 보다. 이것도 믿어야지!
  • Zero dependency: 이건 진짜다. maven dependency가 없다.
  • Thread-safe: 이야~ 멀티쓰레드 환경에서 동시성 문제도 해결해준다.


기본 maven repository에도 등록되어 있다.

  • Apache Maven

<dependency>

  <groupId>net.jodah</groupId>

  <artifactId>expiringmap</artifactId>

  <version>0.5.9</version>

</dependency>


  • Gradle Groovy DSL

implementation 'net.jodah:expiringmap:0.5.9'


  • Gradle Kotlin DSL

compile("net.jodah:expiringmap:0.5.9")



간단한 샘플 예제 몇가지를 살펴보겠다.

  • 맵에 넣을 수 있는 최대 데이터는 1000개이고, 데이터를 입력한지 30초가 지나면 expire되는 맵이다.
  • ExpirationPolicy.CREATED 정책대신에 ExpirationPolicy.ACCESSED 을 적용하면 마지막으로 get()한지 일정시간이 지나면 expire 된다. 즉, LRU(Least Recently Used) 정책을 적용할 수 있다.
// ExpiringMap 생성
Map<String, String> map = ExpiringMap.builder()
.maxSize(1000)
.expirationPolicy(ExpirationPolicy.CREATED)
.expiration(30, TimeUnit.SECONDS)
.build();

map.put("key-1", "value-1");
map.put("key-2", "value-2");
map.put("key-3", "value-3");


  • 맵을 생성할 때 정책을 정하는 것이 아니라, 데이터를 put할 때 적용할 정책을 정할 수 있다. 심지어 각 데이터별로 정책을 다르게 적용할 수 있다.
// ExpiringMap 생성
ExpiringMap<String, String> map = ExpiringMap.builder()
.maxSize(1000)
.build();

map.put("key-1", "value-1", ExpirationPolicy.CREATED, 30, TimeUnit.SECONDS);
map.put("key-2", "value-2", ExpirationPolicy.ACCESSED, 2, TimeUnit.MINUTES);


jar 파일을 까보면 pom.xml 파일까지 포함해서 총 11개 파일이다.
대부분 간단한 정의나 짧은 소스들이며, ExpiringMap 클래스를 구현한 소느는 1000줄이 넘은 다소 긴 소스이다.
필자는 그냥 믿고 잘 쓰고 있어서 ExpringMap.java 소스를 분석하진 않았지만, 이 글을 작성하다 보니 궁금해지긴한다.


맵에 데이터가 입력될 때와 expiring될 때, 원하는 로직을 작성할 수 있는 리스너도 존재한다.

자세한 기능은 GitHub 페이지를 쭉~ 살펴보면 쉽게 파악할 수 있다.
또는 IDE에서 .(점) 입력하면 리스팅되는 메서드들로 쉽게 알 수 있다.
그만큼 쉽게 이용할 수 있다.

반응형