#1. Spring 캐싱
캐싱은 자주 요청되는 데이터를 임시로 저장하여 애플리케이션 성능을 향상시키는 데 중요한 방법입니다.
데이터베이스 검색 및 API 요청과 같은 비용이 많이 드는 작업을 줄여 응답 시간을 단축하고,
백엔드 부담을 줄이며, 사용자 경험을 향상시킵니다.
Spring Boot는 캐싱을 간편하게 구현할 수 있도록 다음과 같은 어노테이션을 제공합니다.
- @Cacheable: 메서드 파라미터를 기반으로 메서드 결과를 캐시합니다.
- @CachePut: 메서드 결과로 캐시를 업데이트합니다
- @CacheEvict: 캐시에서 데이터를 제거합니다
- @Caching: 단일 메서드에 여러 캐싱 어노테이션을 조합할 수 있습니다
#2. Spring 캐시 구현
Spring Boot 애플리케이션에서 캐싱을 활성화하려면 설정 클래스 중 하나에 @EnableCaching 어노테이션을 추가해야 합니다. 이 어노테이션은 각 Spring 빈에서 캐싱 어노테이션을 탐색하는 후처리기를 트리거합니다.
@Configuration
@EnableCaching
public class CacheConfig {
// ...
}
Spring Boot는 기본적으로 ConcurrentHashMap을 사용하여 간단한 인메모리 캐시를 제공합니다.
상품 서비스에 대한 샘플 캐싱 메커니즘을 구현해보겠습니다.
- 상품 모델 정의
@Getter
@ToString
@AllArgsConstructor
public class Product {
private Long id;
private String name;
}
@Cacheable 사용
@Slf4j
@Service
public class ProductService {
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
log.info("getProductById 메소드 수행. id = {}", id);
// 쿼리 수행이 2초 걸린다고 가정한 상황
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Product(id, "제품"+id);
}
}
- 위 예제에서 getProductById 메서드는 @Cacheable 로 어노테이션 처리 되었습니다.
- 특정 id로 메서드를 처음 호출하면 결과가 캐시에 저장됩니다. 동일한 id로 재호출 시 메서드를 재실행하지 않고 캐시에서 결과를 반환합니다.
- 아래와 같은 코드를 통해서 테스트를 진행해봅니다.
@Slf4j
@RestController
@RequestMapping("cache")
@RequiredArgsConstructor
public class CacheController {
private final ProductService productService;
@GetMapping("/get/{id}")
public Product CacheGet(@PathVariable Long id) {
StopWatch stopWatch = new StopWatch("CacheTest");
stopWatch.start("상품 조회");
Product product = productService.getProductById(id);
stopWatch.stop();
log.info(stopWatch.prettyPrint());
return product;
}
}
- 1번 상품을 2번 조회하고 이어서 2번 상품을 한번 조회합니다.
- 1번 상품에 대한 두번째 호출은 캐싱이 되어 응답시간이 줄어든 것을 확인할 수 있습니다.
@Cacheable을 사용한 조건부 캐싱
- @Cacheable 어노테이션의 condition과 unless 속성을 사용하면 캐싱 동작을 조건부로 제어할 수 있습니다.이는 특정 조건에서만 캐시하거나, 특정 조건에서 캐시하지 않도록 처리합니다.
- 예를 들면, id가 10보다 큰 경우에만 캐싱이 발생하도록 설정할 수 있습니다.
@Cacheable(value = "products", key = "#id", condition = "#id > 10")
public Product getProductById(Long id) {
// ...
}
- 이 방식을 통해 불필요한 데이터가 캐시에 저장되는 것을 방지하고, 캐시 공간을 효율적으로 사용할 수 있습니다.
@CachePut을 사용하여 캐시 업데이트
- @CachePut을 사용하면 메서드가 호출될 때마다 캐시를 업데이트할 수 있습니다. 이는 데이터가 변경되었을 때 캐시를 최신 상태로 유지하는 데 유용합니다.
@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
// 상품 업데이트 로직
return product;
}
@CacheEvict를 사용하여 캐시 항목 제거
- @CacheEvict는 캐시에서 특정 항목을 제거하는 데 사용됩니다. 이는 데이터가 더 이상 유효하지 않을 때(ex. 상품 삭제) 캐시를 무효화하는 데 유용합니다.
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
// 상품 삭제 로직
}
- 전체 캐시를 지우려면 allEntries = true 를 사용할 수 있습니다.
@CacheEvict(value = "products", allEntries = true)
public void clearCache() {
// 캐시 초기화 로직
}
추가 구성 및 모범 사례
- 캐시 만료 : 오래된 데이터를 방지하기 위해 캐시 만료 시간을 설정
- 로깅 : 캐시 모니터링을 위해 관련 로깅을 활성화
- 과도한 캐싱 방지 : 자주 접근하고 검색 비용이 높은 데이터만 캐시
- 고유한 캐시 이름 사용 : 멀티 모듈 프로젝트에서 캐시 충돌을 피하기 위해 캐시에 고유한 이름 사용
Spring Boot의 캐싱 기능을 효과적으로 활용하면 애플리케이션의 성능을 크게 향상시킬 수 있습니다.
캐싱 전략을 신중히 계획하고 모범 사례를 따르면 백엔드 부하를 줄이면서 사용자 경험을 개선할 수 있습니다.
'Java > Spring Boot' 카테고리의 다른 글
[Spring Boot] AOP를 활용한 효과적인 trace 및 로깅 구현 방법 (1) | 2025.02.24 |
---|---|
Spring Boot 에서 WebSocket으로 실시간 알림 구현하기 (0) | 2025.02.24 |
Spring Boot 3 + Spring Security 6 + JWT 인증 (0) | 2025.02.06 |
javax.inject.Provider 를 사용할 때 UnsatisfiedDependencyException 발생 (0) | 2023.03.12 |
[Spring Boot] REST API 제작기 - 2.DB연결(Mybatis) (0) | 2022.03.28 |