'iBatis 캐싱'에 해당되는 글 1건

  1. 2008.03.18 iBatis CacheModel(캐시모델) 이해하기
Framework/iBatis2008. 3. 18. 20:13

개발자들이 Application에 도입하는 대부분의 캐싱은 오랜 시간동안 변경되지 않는 데이터를 위한 것이다. 그러나 의외로 캐싱된 데이터가 쓰기에 의해 변경되는 경우도 있다.
개발자들은 나름대로 캐싱모델을 정의하고, 구현하여 사용한다. 그러나 캐싱 될 데이터를 추가하고, 더 이상 사용되지 않는 데이터는 삭제하고, 정해진 시간별로 캐싱 된 데이터를 삭제하는 등의 많은 기능들을 정의하고 구현하여 사용하려고 하는 솔직히 쉬운 일도 아니고, "노력 대비 성능" 또한 보장할 수가 없다.
그래서 요즘 많은 ORM 솔루션들이 데이터 캐싱을 지원한다. iBatis 또한 여타 ORM 솔루션과 같이 데이터 캐싱을 지원한다. 그러나 iBatis의 데이터 캐싱은 다른 ORM 솔루션의 데이터 캐싱과는 조금 개념이 다르다. 여타의 ORM 솔루션들은 주로 DataBase Table 객체에 매핑하는 데 중점을 두고, iBatis는 SQL 구문을 객체에 매핑하도록 되어 있다.

-- CacheModel 이해하기
CacheModel은 iBatis의 모든 캐시 구현체를 정의하는 기반이 되는 곳이다. SQL Maps 설정 안에서 캐시 모델 설정을 정의하고 하나 이상의 쿼리 매핑 구문이 이를 사용할 수 있다.

* CacheModel 속성들 *
id (필수) : 유일한 ID를 지정. CacheModel에 설정 된 캐시를 사용하고 하는 쿼리 매핑 구문에서 ID를 참조한다.
type (필수) : 이 값은 CacheModel이 설정하는 캐시의 타입을 의미한다. 사용 가능한 값으로 MEMORY, LRU, FIFO, OSCACHE가 있다. 이 속성은 사용자 정의 CacheController 구현체의 완전한 클래스 이름으로 지정해도 된다.
readOnly (선택) : 읽기전용 여부. 이 값을 true로 지정하면 캐시가 읽기 전용 캐시로 사용될 것임을 의미한다. 읽기 전용 캐시에서 가져온 객체는 객체의 Property들을 변경할 수 없다.
serialize (선택) : 캐시의 내용을 가져올 때 객체의 모든 값을 복사하여 새로운 객체를 생성하여 전달할지 여부를 지정한다.

여기서 readOnly 속성 값에 대해 좀더 알아보면 readOnly 속성은 단순히 CcheModel에게 캐시된 객체를 어떻게 가져와서 저장할지 알려주는 지시자이다. 이 속성값이 true이면 가져온 내용을 변경해도 CacheModel은 변경되지 않는다. 만약 false로 지정되면 주의해야 하는데 두 명 이상의 사용자가 캐시된 참조의 동일한 인스턴스를 가져갈 수 없음을 의미한다.

* 내장 CacheModel 타입들 *
MEMORY : 단순하게 캐시된 데이터를 가비지 컬렉터가 삭제할 때까지 메모리에 저장한다.
FIFO : 고정 된 크기의 모델로 "first in first out (먼저 들어간 값을 먼저 삭제)" 알고리즘을 사용하여 메모리에서 캐시 항목들을 삭제한다.
LRU : FIFO와 다른 고정 된 크기의 모델로 "least recently used (최근에 가장 오랜동안 사용하지 않은 값을 캐시에서 먼저 삭제)" 알고리즘을 사용하여 메모리에서 캐시 항목들을 삭제한다.
OSCACHE : OpenSymphony Cache를 사용한다. (OSCashe Lib와 설정이 함께해야 한다.)

* readOnly와 serialize 속성의 조합에 대한 요약 *
readOnly (true) / serialize(false) : 성능 좋음. 캐시 된 객체를 가장 빠르게 가져온다. 캐시 된 객체의 공유 인스턴스를 반환하며, 잘못 사용하면 문제를 일으킬 수도 있다.
readOnly (false) / serialize(true) : 성능 좋음. 캐시 된 객체를 빠르게 가져온다. 캐시 된 객체를 깊은 복사 작업을 통해 가져온다.
readOnly (false) / serialize(false) : 주의요망! 캐시는 오직 호출하는 스레드의 세션이 살아있는 동안에만 관련되고, 다른 쓰레드는 사용할 수 없다.
readOnly (true) / serialize(true) : 성능 나쁨. 무의미한 설정이라는 점을 제외하면 readOnly (true) / serialize(true)와 동일하게 작동한다.

readOnly=true이고 serialize=false이면 캐시 된 객체가 전역적으로 공유되기 때문에 모든 사용자는 다른 세션에서 부적절하게 변경 된 객체를 가져오게 될 수 있는 문제의 소지가 있다. readOnly=false이고 serialze=true를 사용하면 캐시에서 가져온 객체의 깊은 복사작업의 결과를 가져오기 때문에 캐시에서 가져온 객체가 값은 비록 같지만 동일한 인스턴스가 아니라는 의미이다. 이것은 캐시에서 가져온 객체의 변경사항이 호출한 세션 안에서만 작용된다.

-- 캐시 비우기 (Cache Flushing)
사용자가 정의 한 CacheModel은 캐시된 데이터를 모두 비울때 사용하는 공통적인 요소를 가지고 있다. 이것은 이전에 캐시된 모든 데이터를 비우고 새롭게 데이터를 캐시하게 된다.

* 캐시를 비우는 flush 요소들 *
<flushOnExecute> : 지정 된 쿼리 매핑 구문이 실행되면 캐시의 모든 데이터를 비운다.
<flushInterval> : 캐시를 비우는 시간 간격을 정의한다.

<flushOnExecute>
속성으로 statement 하나만을 가지며, 이 속성에 지정된 매핑 구문이 실행이 될 때 자동으로 캐시의 데이터를 모두 비운다. 예를 들어 상품카테고리의 카테고리가 추가, 수정, 삭제 될면 이전에 캐시된 신빙성이 떨어지는 데이터를 모두 비우게 할 수 있다.
그러나, 이 속성은 캐시된 데이터를 모두 비우고 새롭게 캐시를 하게 되므로 데이터를 자주 변경하는 매핑 구문에 의존하게 되면 캐시의 효율성이 떨어지게 된다.

   <SqlMap namespace="category">
      <cacheModel id="categoryCache" type="MEMORY">
         ...
         <flushOnExecute statement="category.insert" />
      </cacheModel>
      ...
      <insert id="insert" parameterClass="java.util.Map">
         ...
      </insert>

<flushInterval>
<flushOnExecute> 보다 좀더 간편하게 사용할 수 있는 요소로 시간에 의존하여 지정한 시간이 경과되면 반복적으로 캐시된 데이터를 모두 비운다. 가격은 시(hours),분(minutes),초(seconds) 또는 밀리초(milliseconds)로 지정할 수 있다. <flushInterval>은 하나의 속성만을 허용하기 때문에 5시간 13분 40초와 같이 지정하고 싶다면 초로 계산하여 지정해야 한다. 그리고, 특정 시간을 지정할 수는 없다.

   <cacheModel id="categoryCache" type="MEMORY">
      ...
      <flushInterval hours="12" />
   </cacheModel>

-- CacheModel Properties 설정하기
CacheModel은 플러그인의 형태로 제공되기 때문에 임의의 설정 값을 제공할 수 있는 방법이 필요한데 <property>를 이용하여 처리한다.

* <property> 요소의 속성들 *
name : 필수입력으로 설정할 프로퍼티의 이름
value : 필수입력으로 설정할 프로퍼티의 값

-- CacheModel Type
앞에서 언급했듯이 iBatis에서 사용할 수 있는 CacheModel Type은 MEMORY, LRU, FIFO, OSCACHE 4가지가 있다.

MEMORY
객체 참조를 기반으로 한 캐시이다. 캐시 내의 각 객체의 참조 타입(<reference-type>) 속성을 갖고 있다. 객체의 참조 타입은 가비지 켈렉터에게 객체를 어떻게 다룰지에 대한 힌트를 제공한다. MEMORY CacheModel은 객체에 접근하는 방식보다는 메모리 관리에 중점을 둔 Application에 적합하다.

* MEMORY CacheModel 참조 타입 *
WEAK : 캐시된 데이터를 빨리 비운다. 기본설정 값이며 가비지 켈렉터에 의해 수거되는 것을 막지않고 놔둔다. 이 방식은 일관성 있게 객체에 접근하는 캐시를 사용할 때 잘 적동한다. 캐시를 비우는 비율이 빠른편이기 때문에 메모리 제한을 넘기지 못하도록 보장은 하나 DataBase 접근확률이 높아진다.
SOFT : 메모리 용량이 허락하는 한 캐시된 객체를 보관한다. 가비지 켈렉터는 더 많은 메모리가 필요하다고 판단되기 전까지는 이 객체들을 수거하지 않는다. 메모리 제한을 넘기지 못하도록 보장하며, WEAK 참조보다 DataBase 접근확률은 적은 편이다.
STRONG : 메모리의 한계가 얼마든지 관계없이 객체를 계속 보관한다. 가비지 켈렉터에 의한 수거는 없다. 이 참조타입은 정적이고 작고 장기적으로 사용할 객체를 캐시할 때 유용하다. DataBase 접근확률은 최소할 수 있으나, 캐시되는 객체의 용량이 너무 커져서 메모리 부족이 발생될 수 있다.

   <cacheModel id="categoryCache" type="MEMORY">
      <flushInterval hours="12" />
      <flushOnExecute statement="insert" />
      <property name="reference-type" value="WEAK" />
   </cacheModel>

LRU
가장 최근에  가장 오랫동안 사용되자 않은 것을 제거하는 방식으로 캐시를 관리한다. 캐시의 객체를 제거하는 것은 오직 캐시의 용량이 제한을 넘겼을 때 한번만 발생된다. 특정 객체에 아주 빈번하게 접근하는 캐시를 관리할 때 매우 적합하다. <property> 요소를 사용하여 지정할 수 있는 프로퍼티는 size 하나로 캐시에 저장될 수 있는 최대 개수를 지정한다.

   <cacheModel id="categoryCache" type="LRU">
      <flushInterval hours="12" />
      <flushOnExecute statement="insert" />
      <property name="size" value="200" />
   </cacheModel>

FIFO
먼저 캐시 된 객체를 먼저 삭제한다. 캐시의 객체를 제거하는 것은 오직 캐시의 용량이 제한을 넘겼을 때 한번만 발생된다. 생존기간에 기반을 두고 있기 때문에 초기에 캐시에 저장되는 그 순간에 더 많이 사용되는 객체를 캐싱할때 효과적이다. <property> 요소를 사용하여 지정할 수 있는 프로퍼티는 size 하나로 캐시에 저장될 수 있는 최대 개수를 지정한다.

   <cacheModel id="categoryCache" type="FIFO">
      <flushInterval hours="12" />
      <flushOnExecute statement="insert" />
      <property name="size" value="200" />
   </cacheModel>

OSCACHE
Open Symphoy(http://www.opensymphony.com/oscache)의 OSCache를 사용한다.OSCACHE를 사용하기 위해서는 OSCache 라이브러리와 설정정보가 필요하다.

  <cacheModel id="categoryCache" type="OSCACHE">
      <flushInterval hours="12" />
      <flushOnExecute statement="insert" />
   </cacheModel>

사용자가 만든 캐시 모델
앞에서 언급했듯이 iBatis의 캐시 모델은 플러그인되는 형태여서 사용자가 캐시모델을 만들어서 사용할 수 있다. 사용자가 자신의 캐시모델을 만들기 위해서는 com.ibatis.sqlmap.engine.cache.CacheController 인터페이스를 구현하면 되고, 이름은 alias를 사용하면 된다.

Posted by as.wind.914