Ehcache 적용 방법

Ehcache

- 오픈소스 기반의 빠른 캐시엔진

- Jsr107 Jcache 표준지원

- 경량의 간단한 Local Cache

- 다양한 확장지원

- 분산캐시 지원

-> http://www.ehcache.org/


캐시(Cache)란?

- 데이터 접근을 빠르게 할 수 있도록 미래의 요청에 대비해 데이터를 저장해

  두는 임시 장소를 말한다.


예를 들어 현재 블로그 이용자가 서핑을 하면 페이지 이동이 일어 나고 데이터를 새로

불러 옵니다. 블로그 오른쪽 하단에 글 보관함 같은 경우 페이지 이동이 일어날 때마다

새로 불러오겠지요. 새로운 글이 등록되기 전까지는 해당 년월에 해당하는 게시물 수는 

변하지 않습니다.


* 현재 글 보관함



접속자 수가 더 많아지고(그럴리는없겠지만..) 더 많은 요청이 있을경우 부하도 더 걸리고 

메모리도 더 먹을텐데...


캐시를 사용해서 변동이 많이 없는 데이터에 대해서는 미리 준비해놓으면 속도 및 부하

면에서 얼마나 좋을까.


현재 글 보관함 이 어떻게 되어 있는지 살펴보도록 하겠습니다.


1. 개발환경

 - Spring Framework 4.0.9

 - Ibatis 2.3.4

 - MariaDB 5.5.40

 - Java 1.7

 - Ehcache 2.10.1


2. Maven

 - Ehcache 관련 라이브러리 추가

<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.1</version>
</dependency>


3. Ehcache 환경 설정

 - 설정은 Xml 설정 방법도 있지만 Java 설정 방법으로 하였음.

 - EhCache.java

  1. package egovframework.blog.ehcache;
  2. import org.springframework.cache.CacheManager;
  3. import org.springframework.cache.annotation.EnableCaching;
  4. import org.springframework.cache.ehcache.EhCacheCacheManager;
  5. import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.ComponentScan;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.core.io.ClassPathResource;
  10. @EnableCaching
  11. @Configuration
  12. @ComponentScan(basePackages = "egovframework.blog")
  13. public class EhCache {
  14. @Bean
  15. public CacheManager cacheManager() {
  16. //A EhCache based Cache manager
  17. return new EhCacheCacheManager(ehCacheCacheManager().getObject());
  18. }
  19. @Bean
  20. public EhCacheManagerFactoryBean ehCacheCacheManager() {
  21. EhCacheManagerFactoryBean factory = new EhCacheManagerFactoryBean();
  22. factory.setConfigLocation(new ClassPathResource("./egovframework/ehcache/ehcache.xml"));
  23. factory.setShared(true);
  24. return factory;
  25. }
  26. }

4. 캐시 대상 설정

 - 이름, 저장공간, 유지시간, 제거 알고리즘 등

 - 테스트 이기때문에 절대값은 아닙니다. 자세한 내용은 레퍼런스나 구글 검색.

 - ehcache.xml

글 보관함 캐시 부분 -> name="archiveCache"

<?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"
	monitoring="autodetect"
	dynamicConfig="true"
	>
	
	<diskStore path="java.io.tmpdir"/>
	
	<cache name="archiveCache" 
	    maxEntriesLocalHeap="1000"
	    timeToIdleSeconds="300"
	    timeToLiveSeconds="600"
	    overflowToDisk="false" 
	    memoryStoreEvictionPolicy="LRU" 
	    transactionalMode="off">
	</cache>
	
	
	<cache name="counterCache" 
	    maxEntriesLocalHeap="500"
	    eternal="false" 
	    timeToIdleSeconds="300"
	    timeToLiveSeconds="600"
	    overflowToDisk="false" 
	    memoryStoreEvictionPolicy="LRU" 
	    transactionalMode="off">
	</cache>
	
<!-- 	
	<cache name="recentPostCache" 
	    maxEntriesLocalHeap="2000"
	    timeToIdleSeconds="300"
	    timeToLiveSeconds="600"
	    overflowToDisk="false" 
	    memoryStoreEvictionPolicy="LRU" 
	    transactionalMode="off">
	</cache>
	
	<cache name="recentCommentCache" 
	    maxEntriesLocalHeap="2000"
	    timeToIdleSeconds="300"
	    timeToLiveSeconds="600"
	    overflowToDisk="false" 
	    memoryStoreEvictionPolicy="LRU" 
	    transactionalMode="off">
	</cache>		
 -->	

</ehcache>


5. @Annotation 코드 명시

 - 캐시 명시

  1. /**
  2. * @desc : arc 메인 목록
  3. * @param vo
  4. * @return
  5. * @throws Exception
  6. */
  7. @SuppressWarnings("unchecked")
  8. @Cacheable(value = "archiveCache")
  9. public List> arcMainList(Map param) throws Exception {
  10. return (List>) list("archiveDAO.arcMainList", param);
  11. }

 - 캐시 해제 및 새로운 데이터 생성

등록, 수정, 삭제가 일어날경우 발생되게 설정해놓았다.

  1. /**
  2. * @desc : arc등록
  3. * @param vo
  4. * @throws Exception
  5. */
  6. @CacheEvict(value = "archiveCache", allEntries=true)
  7. public void arcInsert(ArchiveVO vo) throws Exception {
  8. insert("archiveDAO.arcInsert", vo);
  9. }
  10. /**
  11. * @desc : arc수정
  12. * @param vo
  13. * @throws Exception
  14. */
  15. @CacheEvict(value = "archiveCache", allEntries=true)
  16. public void arcUpdate(ArchiveVO vo) throws Exception {
  17. update("archiveDAO.arcUpdate", vo);
  18. }
  19. /**
  20. * @desc : arc삭제
  21. * @param vo
  22. * @throws Exception
  23. */
  24. @CacheEvict(value = "archiveCache", allEntries=true)
  25. public void arcDelete(ArchiveVO vo) throws Exception {
  26. delete("archiveDAO.arcDelete", vo);
  27. }


6. 테스트

 - 캐시가 정말로 동작하는지 테스트 해보겠습니다.

로그를 보면 URL 이 호출되고 SQL이 실행된 다음 글 보관함 목록을 가져옵니다. 

  1. 2016/08/19 17:38:27,770 [http-bio-8080-exec-7] DEBUG egovframework.com.cmm.interceptor.LogInterceptor - Request URI : /blog/arcMainList.do
  2. 2016/08/19 17:38:27,833 [http-bio-8080-exec-7] DEBUG egovframework.com.cmm.service.impl.EgovComAbstractDAO -
  3. 2016/08/19 17:38:27,835 [http-bio-8080-exec-9] INFO jdbc.sqlonly - [ === SQL === ] : select 1
  4. 2016/08/19 17:38:27,841 [http-bio-8080-exec-7] INFO jdbc.sqlonly - [ === SQL === ] :
  5. select
  6. a.arc_id,
  7. date_format(str_to_date(a.arc_id, '%Y%m'), '%Y년 %m월')as arc_id_format,
  8. a.cnt
  9. from
  10. (
  11. select arc_id, count(1) as cnt
  12. from BLOG_ARC
  13. group by arc_id
  14. order by arc_id desc
  15. limit 0, 10
  16. ) a
  17. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |-------|--------------|----|
  18. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |arc_id |arc_id_format |cnt |
  19. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |-------|--------------|----|
  20. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201608 |2016 08 |8 |
  21. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201607 |2016 07 |4 |
  22. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201606 |2016 06 |4 |
  23. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201605 |2016 05 |7 |
  24. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201604 |2016 04 |4 |
  25. 2016/08/19 17:38:27,849 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201603 |2016 03 |2 |
  26. 2016/08/19 17:38:27,850 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201602 |2016 02 |5 |
  27. 2016/08/19 17:38:27,850 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201601 |2016 01 |3 |
  28. 2016/08/19 17:38:27,850 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201512 |2015 12 |2 |
  29. 2016/08/19 17:38:27,850 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |201511 |2015 11 |11 |
  30. 2016/08/19 17:38:27,850 [http-bio-8080-exec-7] INFO jdbc.resultsettable - |-------|--------------|----|


 - 다시 호출햇을경우

URL은 호출되지만 SQL은 실행하지 않습니다. 하지만 글 보관함 목록은 잘 가져왔습니다.

  1. 016/08/19 17:45:07,743 [http-bio-8080-exec-5] DEBUG egovframework.com.cmm.interceptor.LogInterceptor - ====================================== START ======================================
  2. 2016/08/19 17:45:07,743 [http-bio-8080-exec-5] DEBUG egovframework.com.cmm.interceptor.LogInterceptor - Request URI : /blog/arcMainList.do
  3. 2016/08/19 17:45:07,744 [http-bio-8080-exec-5] DEBUG egovframework.com.cmm.interceptor.LogInterceptor - ====================================== END ======================================


EhCache를 필요한곳에 유용하게 사용한다면 정말 좋을거 같습니다.