스프링 캐시(@Cacheable, @CacheEvict)

배세훈·2022년 5월 23일
0

Spring

목록 보기
35/38

캐시 사용

  • 캐시는 서버의 부담을 줄이고 성능을 높이기 위해 사용되는 기술이다. 예를 들면 어떤 요청을 처리하는데 계산이 복잡하거나 혹은 DB에서 조회하는게 오래 걸리는 등에 적용하여 결과를 저장해두고 가져옴으로써 빠르게 처리할 수 있다.

  • 캐시는 값을 저장해두고 불러오기 때문에 반복적으로 동일한 결과를 반환하는 경우에 용이하다. 만약 매번 다른 결과를 돌려줘야 한다면 캐시를 확인하는 작업으로 인한 부하가 생겨 성능이 떨어지게 된다.

스프링 캐시(@Cacheable)

  • 스프링은 AOP 기반으로 캐시가 작동하며 어노테이션으로 AOP 설정을 할 수 있어 간편하게 사용할 수 잇다.
  • 캐시는 저장할 내용과 속성 정보로 메소드의 리턴값과 파라미터를 사용하기 때문에 보통 메소드 단위로 설정하게 되며 클래스나 인터페이스레벨에 캐시를 하는일은 드물다.

Cache 설정

gradle 설정(build.xml)

implementation 'org.springframework.boot:spring-boot-starter-cache'

implementation 'org.hibernate:hibernate-ehcache:5.6.5.Final'

캐시 Config 설정

@EnableCaching
@Configuration
public class CachConfig{
	
    // Eh 캐시 매니저 생성 도우미, 빈등록을 해놓으면 된다.
    @Bean
    public EhCacheManagerFactoryBean cacheManagerFactoryBean(){
    	return new EhCacheManagerFactoryBean();
    }
    
    // EhcacheManager 등록
    @Bean
    public EhCacheCacheManager ehCacheCacheManager(){
    	// 캐시 설정
        CacheConfiguration conf = new CacheConfiguration()
        .eternal(false)
        .timeToIdleSeconds(0)
        .timeToLiveSeconds(21600)
        .maxEntriesLocalHeap(0)
        .memeoryStoreEvictionPolicy("LRU")
        .name("layoutCaching");
        
        // 설정을 가지고 캐시 생성
        Cache layoutCache = new net.sf.ehcache.Cache(conf);
        
        // 캐시 팩토리에 생성한 eh캐시를 추가
        Objects.requireNonNull(cacheManagerFactoryBean().getObject()).addCache(layoutCache);
        
        // 캐시 팩토리를 넘겨서 eh캐시 매니저 생성
        return new EhCacheCacheManger(Objects.requireNonNull(cacheManagerFactoryBean().getObject()));
    }
    
}

필수 설정 요소

요소 설명
EhCacheManagerFactoryBean CacheManger의 적절한 관리 및 인스턴스를 제공하는데 필요하며 EhCache 설정 리소스를 구성한다.
maxEntriesLocalHeap Heap 캐시 메모리 pool size 설정, 가비지 컬렉션 대상이 됨.
memoryStoreEvictionPolicy 캐시가 가득찼을때 관리 알고리즘 설정 default "LRU"
timeToLiveSeconds Element가 존재하는 시간. 이 시간이 지나면 캐시에서 제거된다. 이 시간이 0이면 만료시간을 지정하지 않는다.
timeToIdleSeconds Element가 지정한 시간 동안 사용(조회)되지 않으면 캐시에서 제거된다. 이 값이 0인 경우 조회 관련 만료 시간을 지정하지 않는다.
eternal true일 경우 timeout 관련 설정이 무시, element가 캐시에서 삭제되지 않음.
name 캐시명

@Cacheable 사용방법

  • 캐시에 데이터가 없을 경우에는 기존의 로직을 실행한 후에 캐시에 데이터를 추가하고 캐시에 데이터가 있으면 캐시의 데이터를 반환한다.
@Cacheable("top10")
public Book getTop10(String bookNum){
}
  • 동작 순서
  1. getTop10(1) 처음 호출
    a. top10 캐시에 bookNum(1)에 해당하는 값이 있는지 확인(처음 호출이라 값 X)
    b. top10 캐시에 값이 없으므로 해당 로직을 실행하여 값을 반환한다.
    c. 반환한 값을 캐시에 bookNum(1)의 value로 저장한다.
  2. getTop10(1) 두번째 호출
    a. top10 캐시에 bookNum(1)에 해당하는 값이 있는지 확인한다.(값 존재)
    b. top10 캐시에 값이 있으므로 해당 로직을 실행하지 않고 캐시에서 조회한 값을 반환한다.
  3. getTop10(2) 세번째 호출(bookNum 변경)
    a. top10 캐시에 bookNum(2)에 해당하는 값이 있는지 확인한다.(값 X)
    b. top10 캐시에 값이 없으므로 해당 로직을 실행하여 값을 반환한다.
    c. 반환한 값을 캐시에 bookNum(2)의 value로 저장한다.

만약 메소드의 파라미터가 없다면 0이라는 디폴트 값을 Key로 사용하여 저장한다. 그리고 만약 메소드의 파라미터가 여러 개라면 파라미터들의 hashCode 값을 조합하여 키를 생성한다.

  • 여러개의 파라미터 중 1개의 키 값으로 지정할 때
@Cacheable(value = "top10", key = "#bookNum")
public Book getTop10(Long bookNum, User user){}
  • key 값의 지정에는 SpEL이 사용된다. 파라미터가 객체라면 다음과 같이 하위 속성에 접근 가능하다.
@Cacheable(value = "top10", key="#book.bookNum")
public Book getTop10(Book book, User user){}
  • 파라미터 값이 특정 조건인 경우에만 캐시를 적용하기를 원한다면 condition을 이용하면 된다.
@Cacheable(value = "top10", key = "#book.bookNum", condition = "#user.type == 'USER'")
public Book getTop10(Book book, User user){}
  • 파라미터 변경하여 캐시를 적용하기를 원한다면 java 코드로 설정하여 이용하면 된다.
// 캐시 적용할 메소드
@Cacheable(value = "top10", key = "T(com.test.cache.config).genKey(#searchOp)")
public Book getTop10(Map<String, Object> searchOp){}
// 파라미터 변경하는 설정
// com.test.cache.config.genKey 메소드
public static String genKey(MultiValueMap<String, Object> searchOp){
	MultiValueMap<String, Object> clonObj = new LinkedMultiValueMap<>();
    clonObj.addAll(searchOp);
    
    String gsonStr = new Gson().toJson(clonObj).replaceAll("!\#[$\%&\\(\\)", "")
    
    return gsonStr;
}

캐시 제거(@CacheEvict)

  • @CacheEvict에 캐시 이름을 넣어주면 메소드가 실행될 때 캐시의 내용이 제거된다.
// top10라는 이름의 캐시를 초기화
@CachEvict(value = "top10")
public void clearTop10(){}
  • @CacheEvict는 기본적으로 메소드의 키에 해당하는 캐시만 제거한다.
// bookNum와 같은 키 값을 가진 캐시만 제거된다.
@CacheEvict(value = "top10", key = "#book.bookNum")
public void updateBook(Book book){}
  • 캐시에 저장된 값을 모두 제거할 때
@CacheEvict(value="top10", allEntires = true)
public void clearTop10(){}
profile
성장형 인간

0개의 댓글