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

안녕하세요, 하마연구소입니다.

자바 프로그래밍을 하다보면 콜렉션(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에도 등록되어 있습니다.

<dependency>
  <groupId>net.jodah</groupId>
  <artifactId>expiringmap</artifactId>
  <version>0.5.9</version>
</dependency>

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줄이 넘은 다소 긴 소스코드 입니다. 

맵에 데이터가 입력될 때와 expiring될 때, 원하는 로직을 작성할 수 있는 리스너도 존재합니다.
자세한 기능은 GitHub 페이지를 쭉~ 살펴보면 쉽게 파악할 수 있으며, 그만큼 쉽게 이용할 수 있습니다.

지금까지 유용한 기능을 가진 ExpiringMap을 간단하게 소개하였습니다.
감사합니다.

댓글

Popular Posts

AI 시대, SEO가 아닌 GEO에 포커싱해야 하는 이유

AI 메모리 HBM 외에 HBF도 주목

네이버 쇼핑 잘 나가네요, 구팡이 절대 강자인줄~