주요글: 도커 시작하기
반응형
Jakarta Commons Collection API의 LRUMap을 사용하여 LRU 캐시를 구현해본다.

LRUCacheEngine의 구현

Jakarta Common Collection API에서 제공하는 org.apache.commons.collections.LRUMap은 다른 맵과 달리 지정된 크기를 갖는다. 즉, 예를 들어 다음의 코드를 보자.

    
    LRUMap map = new LRUMap(3);
    
    map.put("key1", value1);
    map.put("key2", value2);
    map.put("key3", value3);
    map.put("key4", value4);

위 코드는 크기가 3인 LRUMap을 생성한 후, put() 메소드로 4개의 <키, 값> 매핑을 저장하였다. 다른 맵 같으면 맵의 저장공간을 확장한 후 "key4"에 대한 매핑 정보를 저장하겠지만, LRUMap은 지정된 크기 이상으로 저장공간이 증가하지 않는다. 대신, 기존에 존재하던 <키, 값> 매핑 정보 중에서 한개를 삭제한 후 새로운 <키, 값> 쌍을 삽입한다. 이때, 기존에 존재하던 <키, 값> 매핑 중에서 어떤 것을 제거할 지의 여부를 결정해야 하는데, LRUMap은 LRU 알고리즘을 사용한다. LRU 알고리즘은 가장 최근에 사용한 것을 기준으로해서 삭제할 객체를 결정하는 알고리즘으로서 캐시에서 주로 사용되는 알고리즘 중의 하나이다. 캐시와 LRU 알고르짐에 대한 내용은 자바캔에 필자가 기고한 기사인 '캐시를 이용한 성능 향상!'에 설명되어 있으니 참고하기 바란다.

LRUMap은 그 근본이 LRU 캐싱과 동일하기 때문에 LRUMap을 사용하면 매우 쉽게 LRU 캐시 엔진을 구현할 수 있다. '캐시를 이용한 성능 향상!'에 캐싱 엔진의 설계를 보여주었으므로 본 글에서는 이 글에서 소개한 클래스도를 기반으로 LRUCacheEngine을 작성해볼 것이다. 참고로 Commons Collection API는 자카르타의 다운로드 사이트인 http://jakarta.apache.org/site/binindex.cgi에서 구할 수 있다. 이 사이트에서 Commons Collection API를 다운로드 받은 후 압축을 풀면 commons-collections.jar 파일을 발견할 수 있을 것이다. 이 파일을 클래스패스에 추가하면 Commons Collection API가 제공하는 org.apache.commons.collections.LRUMap 클래스를 사용할 수 있다.

먼저 작성할 것은 캐시에 저장될 데이터를 읽어올 때 사용될 ObjectFetcher 이다. ObjectFetcher는 인터페이스로서 다음과 같이 키에 대한 객체를 리턴해주는 메소드를 선언하고 있다.

   public interface ObjectFetcher {
       public Object fetch(Object key);
   }

ObjectFetcher는 캐시엔진이 캐싱되어 있는 객체 중에서 원하는 객체를 찾을 수 없는 경우에 원하는 객체를 읽어오기 위해 사용된다. 캐시 엔진은 객체를 캐싱할 저장소로 LRUMap을 사용하는데, LRUMap을 이용한 캐시 엔진은 다음과 같다.

   import org.apache.commons.collections.LRUMap;
   
   /**
    * Jakarta Collections의 LRUMap을 사용해서
    * LRU 알고리즘 기반의 캐시를 구현한 엔진
    */
   public class LRUCacheEngine {
       
       private LRUMap map = null;
       
       private ObjectFetcher fetcher = null;
       private int hit;
       private int fail;
       private int totalAccess;
       
       public LRUCacheEngine(int size, ObjectFetcher fetcher) {
           if (size < 1) throw new IllegalArgumentException("size < 1");
           
           hit = 0;
           fail = 0;
           totalAccess = 0;
           this.fetcher = fetcher;
           map = new LRUMap(size);
       }
       
       /**
        * 캐시로부터 객체를 구해온다.
        */
       public Object get(Object key) {
           totalAccess ++;
           
           Object obj = map.get(key);
           if (obj == null) {
               fail ++;
               obj = fetcher.fetch(key);
               if (obj != null) {
                   map.put(key, obj);
               }
           } else {
               hit ++;
           }
           return obj;
       }
       
       public int getTotalAccess() {
           return totalAccess;
       }
       
       public int getHit() {
           return hit;
       }
       
       public int getFail() {
           return fail;
       }
   }

org.apache.commons.collections.LRUMap 사용함으로써 LRU 알고리즘을 구현하지 않아도 되므로 LRU Cache를 구현하는 것이 매우 간단해졌다.

LRUCacheEngine을 사용할 때에는 ObjectFetcher 인터페이스를 알맞게 구현한 Fetcher만을 작성해주면 된다. 예를 들어, 다음은 매우 간단한 ObjectFetcher의 예이다.

   public class SimpleObjectFetcher implements ObjectFetcher {
       public Object fetch(Object key) {
           return new String(key.toString()+" 값");
       }
   }

위의 SimpleObjectFetcher는 key가 들어오면 해당 그 키를 String 타입으로 변환한 후 " 값" 문자열을 연결한다. 예를 들어, 정수값 7에 해당하는 Integer 객체가 key로 들어오면 리턴되는 객체는 "7 값"이 되는 것이다.

캐싱될 객체를 읽어오는(또는 생성하는) ObjectFetcher를 알맞게 구현했다면 이제 캐시를 다음과 같이 사용하면 된다.

   ObjectFetcher fetcher = new SimpleObjectFetcher();
   ...
   LRUCacheEngine cache = new LRUCacheEngine(100*1024, fetcher); // 100K 개의 객체 저장 캐쉬
   ...
   // 객체가 필요할 때 engine.get() 메소드를 사용한다.
   String obj = (String)cache.get(key);

응용에 대하여

본 글에서는 Jakarta Commons API에서 제공하는 LRUMap을 사용하여 LRU 알고리즘에 기반한 간단한 캐싱 엔진을 구현해보았다. 완전한 캐싱 엔진으로서는 부족한 점이 있지만 본 장에서 설명한 소스 코드에 약간의 노력을 곁들이면 일반 어플리케이션에서 훌륭하게 사용할 수 있는 캐싱 엔진을 제작할 수 있을 것이다. 특히, 캐싱 엔진은 컴퓨터와 관련된 모든 곳에서 성능을 높이기 위해서 사용되는 기법인 만큼 이미 그 효과는 검증되어 있다 할 수 있다. 그러므로, 여러분도 본장의 예제를 기반으로 여러분의 어플리케이션에 알맞은 캐시를 구현한다면 고성능의 어플리케이션의 제작할 수 있게 될 것이다.

관련링크:

+ Recent posts