Ehcache로 캐싱하기

2024. 8. 2. 15:12· 프로젝트 Project
목차
  1. 1️⃣ 캐싱 전략
  2. ✔️ 캐시 메모리 제거
  3. ✔️ 캐시 데이터 만료 시간 설정
  4. 2️⃣ 구현
  5. ✔️ 설정
  6. ✔️ 캐싱 구현

프로젝트의 규모나 성격, 도메인에 따라 사용할 수 있는 캐싱 전략은 다양합니다.

카테고리를 전체 조회하는 저의 서비스의 경우, 데이터가 자주 조회됨/변경이 자주 일어나지 않음/용량이 크지 않음 이라는 특성을 가지고 있기 때문에 캐싱을 사용하기로 하였습니다.

또한 단일 서버를 사용하고 있으므로 로컬 인메모리로 캐싱하는 Ehcache를 사용하여 빠르게 카테고리 데이터에 접근할 수 있도록 구현하였습니다.

 

1️⃣ 캐싱 전략

카테고리는 조회가 잦지만 수정이 잦지 않다는 점, 그리고 데이터 변경사항에 민감하지 않다는 점을 고려해 가장 일반적으로 쓰이는 look aside + write around 조합(데이터 정합성 이슈가 있음)을 사용할 것입니다. 

자세한 캐싱 전략 참고

✔️ 캐시 메모리 제거

  • 어플리케이션의 로컬 인메모리를 사용하는 만큼 캐시된 데이터의 용량을 관리하는 것이 중요합니다. 디폴트 캐시 설정으로 가장 오랫동안 사용이 되지 않은 항목을 먼저 제거하는 LRU 알고리즘을 사용하였습니다.
  • 단, 카테고리의 경우에는 단일 데이터이며 cache miss가 있을 때에만 데이터를 저장하기 때문에 큰 의미가 없습니다.

💡 그 외의 알고리즘

  • LFU 알고리즘: 가장 적게 액세스된 항목을 먼저 제거
  • FIFO 알고리즘: 가장 오래된 항목을 먼저 제거

 

✔️ 캐시 데이터 만료 시간 설정

  • 쓰기로 write around 전략(cache miss가 있을 때 캐시저장소에 데이터 저장)을 사용하기 때문에 cache miss의 주기를 관리해주어야 합니다.
  • 카테고리의 경우 자주 변경되는 사항이 아니므로 캐시 만료 시간을 1시간으로 설정하였습니다.

 


2️⃣ 구현

Srping boot3, gradle 9, java 17 환경입니다.

✔️ 설정

글로벌 설정

spring:
  cache:
    ehcache:
      config: classpath:ehcache.xml
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'net.sf.ehcache:ehcache:2.10.3'

 

Ehcache 설정

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="0"
            eternal="false"
            statistics="false"
            timeToIdleSeconds="10"
            timeToLiveSeconds="10"
            overflowToDisk="false"
            diskPersistent="false"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="categoryFindService.findAll"
            maxElementsInMemory="100"
            maxElementsOnDisk="0"
            eternal="false"
            statistics="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            overflowToDisk="false"
            diskPersistent="false"
            memoryStoreEvictionPolicy="LRU">
            
            <cacheEventListenerFactory class="com.blabla.config.CacheEventFactory" />
            
    </cache>

</ehcache>
  • maxElementsInMemory: 디스크가 아닌 인메모리를 사용하여 최대 저장할 수 있는 요소 수를 설정합니다.
  • memoryStoreEvictionPolicy: LRU 데이터 제거 알고리즘을 사용합니다.
  • cacheEventListenerFactory : 분산 서버 또는 필요에 의해 캐시에 대한 정보를 로그로 남기기 위한다면, 캐시 이벤트 리스너를 등록하여 로깅클래스를 생성해 정보를 확인할 수 있습니다.

 

@Configuration
@EnableCaching
public class EhcacheConfiguration {

}
@Slf4j
public class CacheEventLogger implements CacheEventListener<Object, Object> {

    @Override
    public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
        log.info("cache event logger message. getKey: {} / getOldValue: {} / getNewValue:{}", cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
    }
}

 

✔️ 캐싱 구현

**@Cacheable(value = "categoryFindService.findAll")**
@Transactional(readOnly = true)
public List<CategoryFindResultDto> findCategoriesUsingCache() {
    List<Category> categories = categoryRepository.findAll();
    return categories.stream()
            .map(CategoryFindResultDto::from)
            .toList();
}

저의 경우에는 조건이 필요없는 동일한 데이터셋를 조회하기 때문에 key설정이 필요 없었습니다.

하지만 여러 데이터셋을 조회하는 경우에는 아래와 같이 캐시의 키를 통해 다른 데이터셋을 가져올 수 있습니다.

 

**@Cacheable(value = "categoryFindService.findAll", 
						key = "#request.requestURI + '-' + #pageNo",
						condition = "#pageNo <= 5")**
@Transactional(readOnly = true)
public List<CategoryFindResultDto> findCategoriesUsingCache() {
    List<Category> categories = categoryRepository.findAll();
    return categories.stream()
            .map(CategoryFindResultDto::from)
            .toList();
}
  • key : 캐시를 구분하기 위한 용도입니다. SpEL과 메소드의 파라미터를 이용해 사용해 키를 동적으로 생성할 수 있습니다.
  • condition: 캐시가 적용되기 위한 조건을 지정합니다. SpEL 식이 true 일때만 캐시 처리가 적용됩니다.

'프로젝트 Project' 카테고리의 다른 글

static 내부 클래스로 DTO 관리하기  (0) 2024.08.06
Spring Security + JWT로 로그인 구현하기 (1)  (0) 2024.08.05
멀티 모듈로 프로젝트 구성하기  (0) 2024.08.05
쿼리 튜닝하기  (0) 2024.08.02
인덱스 적용하기  (0) 2024.08.02
  1. 1️⃣ 캐싱 전략
  2. ✔️ 캐시 메모리 제거
  3. ✔️ 캐시 데이터 만료 시간 설정
  4. 2️⃣ 구현
  5. ✔️ 설정
  6. ✔️ 캐싱 구현
'프로젝트 Project' 카테고리의 다른 글
  • Spring Security + JWT로 로그인 구현하기 (1)
  • 멀티 모듈로 프로젝트 구성하기
  • 쿼리 튜닝하기
  • 인덱스 적용하기
달래dallae
달래dallae
백엔드를 열심히 갈고 닦아서 광내봅시다 ~_~
달래dallae
머루랑달래랑
달래dallae
전체
오늘
어제
  • 분류 전체보기 (54)
    • 프로젝트 Project (14)
    • 백엔드 Backend (27)
      • 기본 개념 (13)
      • 서버 Server (9)
      • 스프링 Spring (1)
      • JPA (3)
    • 데이터베이스 Database (6)
      • MySQL (1)
      • Oracle (5)
    • 언어 Language (0)
      • 자바 Java (0)
      • 파이썬 Python (0)
    • 알고리즘 Algorithm (1)

블로그 메뉴

  • 홈
  • 글쓰기
hELLO · Designed By 정상우.v4.2.2
달래dallae
Ehcache로 캐싱하기
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.