본문 바로가기

Java & Spring

Spring boot 에서 ehcache 사용하기

자바 Spring boot에서 ehcache 사용하기.

캐시란? 데이터를 쌓아두고 원하는 데이터를 바로 찾을 수 있도록 key를 부여하여 해당 키를 캐시에 넘기면 그에 해당하는 데이터가 반환되게 하는 것이다.

spring에서 읽기가 자주 발생하고 작업의 부하가 클 경우 캐시를 사용하면 서버의 오버헤드를 줄일 수 있다.

1. EhCache를 사용하기 위한 설정

Gradle 의존성 추가
dependencies {
	compile('org.springframework.boot:spring-boot-starter-cache')
	compile 'net.sf.ehcache:ehcache-core:2.10.3'
}


src/main/resources/ehcache.xml 추가

  <cache
     name="product",
     maxEntriesLocalHeap="5000"
     eternal="false"
     timeToIdleSeconds="0"
     timeToLiveSeconds="30"
     maxEntriesLocalDisk="0"
     overflowToDisk="false"
     statistics="true"
     memoryStoreEvictionPolicy="LRU"
     transactionalMode="off"     
  />         

어플리케이션 설정
@SpringBootApplication
@EnableCaching // 캐시사용 선언
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 상품 조회 샘플 코드를 이용한 EhCache 적용


상품 정보를 조회하는 샘플 코드를 만들어 캐시 효과를 알아보겠습니다.

주어진 partNumber를 이용하여 상품의 상세정보를 조회하는 api입니다. 

getProductDetail 메소드의 수행시간을 체크하는 것을 보실 수 있습니다. 


상품 조회 샘플 API

@RestController
public class ProductController {

	@Autowired
	private ProductService productService;

	@RequestMapping(value = "/product/{partNumber}", method = RequestMethod.GET)
	public Product getProductDetail(@PathVariable("partNumber")  String partNumber) throws Exception {
		long start = System.currentTimeMillis(); // 수행시간 측정
		Product result =  productService.getProductDetail(partNumber); // 상품정보 조회
		long end = System.currentTimeMillis();

		System.out.println(partNumber + "수행시간 :" + (end-start) + "ms");

		return result;
	}
}

캐시 적용하기

getProductDetail 메소드에서는 부하가 큰 작업이 있다고 가정합니다. Thread.sleep(1000)으로 1초의 작업시간이 걸린다고 가정하겠습니다. 캐시를 적용하기 위해선 @Cacheable 어노테이션을 설정하고 value(캐시 이름)과 key를 설정합니다. 아래 예에선 product 캐시와 key를 인자로 넘어온 partNumber로 설정하였습니다.  

@Service
public class ProductService {

	@Cacheable(value = "product", key="#partNumber")
	public Product getProductDetail(String partNumber) throws Exception {
		Product product = new Product();
		product.setPartNumber(partNumber);
		Thread.sleep(1000); // db 조회 및 각종 비즈니스 로직이 동작한다고 가정

		return product;
	}	
}

캐시 결과
아래 실행 결과를 보면 상품이 첫번째 호출할 때는 1초이상이 걸리지만 그 이후에 같은 상품을 또 호출할 경우에는 0-1ms의 응답속도를 보이는 것을 확인할 수 있습니다.
product0의 수행시간 :1004ms
product0의 수행시간 :0ms
product0의 수행시간 :0ms
product0의 수행시간 :1ms
product5의 수행시간 :1002ms
product5의 수행시간 :0ms
product5의 수행시간 :0ms
product5의 수행시간 :0ms
product7의 수행시간 :1001ms
product7의 수행시간 :0ms
product7의 수행시간 :0ms
product7의 수행시간 :0ms


ehcache configuration

Name 

Value 

Default 

 maxEntriesLocalHeap

 힙의 최대 항목 수 0 = 무제한

 0

 eternal

 true 인 경우 timeToLiveSeconds 및 timeToIdleSeconds가 무시

 false

 timeToIdleSeconds

 요소가 액세스되지 않고 캐시에 존재할 수있는 최대 시간 (초) 0 = 무제한

 0

 timeToLiveSeconds

사용에 관계없이 요소가 캐시에 존재할 수있는 최대 시간 (초) 0 = 무제한

 0

 maxEntriesLocalDisk

 디스크에 오버플로되는 최대 캐시

 0

 diskExpiryThreadIntervalSeconds

 사용에 관계없이 요소가 디스크에 존재할 수있는 최대 시간 (초) 0 = 무제한 

 0

 memoryStoreEvictionPolicy

 LFU, LRU, FIFO

 LRU