티스토리 뷰

cache는 거의 변경될 여지가 없는 DB 조회 결과값을 메모리 혹은 디스크에 보관하고 있다가 다시 호출되었을때는 DB 조회를 하지 않고 메모리에 있는 결과값을 그대로 쓰고 싶을때 사용한다. 많은 cache 관련 lib들이 있지만 가장 대표적으로 많이 사용되고 있는 ehcache를 springboot와 연동하고 사용하는 방법에 대해서 기술해보고자 한다. 

필자는 springboot 2.3.x, java11, maven, ehcache 2.x 환경이다. 


설정

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.6</version>
</dependency>

가장 먼저 해야 할 일은 dependency를 추가하는 일이다. springboot에서 간편히 cache를 사용하기 위한 spring-boot-starter-cache와 cache중에서도 ehcache를 사용하기 위해 ehcache dependency를 추가해준다. 

 

ehcache.xml

ehcache를 사용하기 위해서는 ehcache.xml에 ehcache 설정을 해줘야 한다. java config로도 할 수 있을텐데 이것은 다음에 시간적 여유가 있을때 변환을 해봐야할것 같고 지금은 xml 파일 그대로 사용하도록 하겠다.  ehcache.xml 파일은 기본적으로 src/main/resources 하위에 위치시키도록 한다. 만약 다른 위치에 놓고 사용하고 싶다면 application.yml 에서 spring.cache.ehcache.config=classpath:ehcache.xml 부분을 변경하여 사용하도록 하자. 

java config로 적용하는 방법은 이 글을 참조하도록 하자. 

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
    updateCheck="false">
    
    <diskStore path="java.io.tmpdir" />
    
    <cache name="getMenu"
           maxEntriesLocalHeap="1000"  
           maxEntriesLocalDisk="10000" 
           eternal="false"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="1800" timeToLiveSeconds="1800"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
           <persistence strategy="localTempSwap" />
    </cache>
</ehcache>

메뉴를 조회하는 getMenu라는 기능에 대해 cache를 해보려 한다. cache 설정의 의 각 property 값은 다음과 같다. 

property desc
maxEntriesLocalHeap 메모리에 생성될 객체의 최대 수(0: 제한없음)
maxEntriesLocalDisk 디스크(DiskStore)에 저장될 객체의 최대 수(0: 제한없음)
eternal 저장된 캐시를 제거할지 여부. 설정이 true 인 경우 저장된 캐시는 제거되지 않으며 timeToIdleSeconds, timeToLiveSeconds 설정은 무시
timeToIdleSeconds 생성후 해당 시간 동안 캐쉬가 사용되지 않으면 삭제, 0은 삭제되지 않음
timeToLiveSeconds 생성후 해당 시간이 지나면 캐쉬는 삭제. 0은 삭제되지 않음
diskSpoolBufferSizeMB 디스크 캐시에 쓰기 모드로 들어갈때, 사용될 비동기 모드의 스폴 버퍼 크기 설정.(OutOfMemory 에러가 발생 시 설정한 크기를 낮추는 것이 좋음)
memoryStoreEvictionPolicy maxEntriesLocalHeap 설정 값에 도달했을때 설정된 정책에 따라 객체가 제거되고 새로 추가(LRU : 사용이 가장 적었던 것부터 제거, FIFO : 먼저 입력된 것부터 제거, LFU : 사용량이 적은 것부터 제거)
persistence strategy diskStore 사용 설정("localTempSwap": Temp DiskStore 사용, "none": Only Memory 사용)

이렇게 각자 상황에 맞게 설정을 해준다. 

 

CacheConfig.java

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;

@EnableCaching
@Configuration
public class CacheConfig {}

설정해놓은 cache를 사용하겠다는 정의를 내리기 위해 CacheConfig 클래스를 생성하여 @EnableCaching 을 달아준다. 


사용법

SampleMenuService.java

@Cacheable(value = "getMenu", key = "#menuMap")
public Map<String, String> getMenu(Map<String, Object> menuMap){
    Map<String, String> menu = (Map<String, String>)getSqlSession().selectList("sampleMenuService.getMenu", menuMap);
    return menu;
}

@Cacheable을 사용하여 해당 메소드의 결과값은 cache에 담겠다고 선언을 한다. 이렇게 선언을 하면 최초 이 메소드가 호출이 되면 DB에 접근하여 결과값을 menuMap이라는 key값으로 cache에 쌓는다. value는 ehcache.xml 파일에서 정의한 cache의 name과 일치시켜주면 된다. 

이렇게 했을때 최초에만 sampleMenuService.getMenu 쿼리를 수행하고 그다음부터는 수행하지 않아야 정상이다. 

 

 

 

사용을 하다가 menu를 변경했을때는 기존의 cache를 clear해주고 새로 caching을 해줘야 한다. 그럴때는 다음과 같이 해주면 된다.

@CacheEvict(value = "getMenu", allEntries=true)
public SampleMenu saveMenu(SampleMenu menu) {
...

@CacheEvict를 활용하여 기존에 caching되고 있는 getMenu 라는것을 날려주도록 하자. 

 

끝!

 

 


참조 : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html

 

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31