⭐ 캐시 추상화란?
캐시 추상화는 개발자가 캐싱을 효과적으로 활용할 수 있도록 다양한 캐시 구현체를 추상화하는 개념입니다. 이를 통해 코드에서 캐시를 직접 관리하지 않고도 데이터를 캐싱할 수 있어, 성능 최적화와 코드 간결성을 동시에 얻을 수 있습니다.
✅ 왜 캐시 추상화가 필요한가?
캐시 추상화는 다음과 같은 이점을 제공합니다:
- 코드의 유연성: 캐싱 로직을 비즈니스 로직에서 분리하여 관리할 수 있습니다.
- 캐시 구현의 독립성: 캐시 제공자(Redis, Ehcache, Caffeine 등)를 쉽게 교체할 수 있습니다.
- 일관된 캐시 인터페이스: 다양한 캐시 기술을 하나의 통합된 인터페이스로 사용하여 일관성 있는 코드를 유지할 수 있습니다.
⭐ Spring에서의 캐시 추상화
Spring 프레임워크에서는 @Cacheable, @CachePut, @CacheEvict 등의 어노테이션을 통해 캐시를 쉽게 설정할 수 있습니다. 이를 통해 캐시 저장, 갱신, 삭제와 같은 작업을 간단하게 수행할 수 있습니다.
- @Cacheable: 메서드 호출 시 캐시를 먼저 확인하고, 없을 경우 데이터를 새로 생성하여 캐시에 저장합니다.
- @CachePut: 메서드 실행 후 항상 캐시에 값을 갱신합니다.
- @CacheEvict: 특정 조건에 따라 캐시를 삭제하여 데이터의 최신성을 유지합니다.
✅ 캐시 구현체 예시
Spring은 여러 캐시 구현체와 연동할 수 있습니다:
- Ehcache: 자바 기반의 영구 저장 캐시.
- Caffeine: 고성능 인메모리 캐시.
- Redis: 분산 캐시로, 데이터를 네트워크상에 저장하여 여러 애플리케이션에서 접근 가능.
✅ 실제 활용 예제: Spring 캐시 추상화 적용하기
다음 예제에서는 사용자 정보를 데이터베이스에서 가져오는 메서드에 캐시를 적용해보겠습니다. 데이터베이스에 동일한 사용자 정보를 자주 요청하는 상황을 가정하고, 캐시 추상화를 통해 데이터베이스 조회 빈도를 줄이는 방법을 보여줍니다.
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 캐시가 활성화된 메서드
@Cacheable(value = "userCache", key = "#userId")
public User getUserById(Long userId) {
System.out.println("Fetching user from database with ID: " + userId);
return userRepository.findById(userId).orElse(null);
}
}
위 코드에서는 @Cacheable 어노테이션을 사용하여 getUserById 메서드에 캐시를 설정했습니다.
- @Cacheable(value = "userCache", key = "#userId"): value는 캐시의 이름으로, 여러 캐시를 운영할 때 캐시를 구분할 수 있도록 합니다. key는 캐시를 식별할 기준으로 사용됩니다. 여기서는 userId를 캐시 키로 사용하고 있습니다.
- getUserById 메서드: 해당 메서드를 호출할 때마다 캐시에서 먼저 userId에 해당하는 데이터가 있는지 확인하고, 없을 경우 데이터베이스에서 정보를 가져와 캐시에 저장합니다.
이제 동일한 userId로 getUserById 메서드를 호출하면, 캐시에 저장된 값을 반환하므로 데이터베이스를 중복해서 조회하지 않습니다. 이는 조회 빈도를 줄이고 응답 속도를 향상시킵니다.
✅ 캐시 무효화 및 갱신
때로는 데이터가 변경될 때 캐시를 비우거나 갱신해야 할 때가 있습니다. 이를 위해 @CacheEvict와 @CachePut 어노테이션을 사용할 수 있습니다.
캐시 무효화 (@CacheEvict)
- 사용자의 정보를 삭제하거나 갱신할 때, 캐시에 저장된 정보를 제거하고 최신 정보를 가져올 필요가 있습니다. 예를 들어, 사용자 삭제 시 캐시를 무효화하는 방법은 다음과 같습니다.
@CacheEvict(value = "userCache", key = "#userId")
public void deleteUser(Long userId) {
userRepository.deleteById(userId);
System.out.println("User deleted and cache evicted for ID: " + userId);
}
- 이 코드는 사용자를 삭제하면서 해당 userId의 캐시 데이터를 제거합니다.
캐시 갱신 (@CachePut)
- 사용자 정보가 변경될 때마다 캐시를 갱신하고 싶다면 @CachePut을 사용할 수 있습니다.
@CachePut(value = "userCache", key = "#user.id")
public User updateUser(User user) {
User updatedUser = userRepository.save(user);
System.out.println("User updated and cache refreshed for ID: " + user.getId());
return updatedUser;
}
- 이 코드에서는 updateUser 메서드를 호출할 때마다 캐시에 최신 데이터가 저장되도록 합니다.
⭐ 캐시 추상화의 효과
캐시 추상화를 도입하면 데이터베이스 부하를 줄이고 응답 속도가 향상됩니다. 캐시 사용 여부는 설정에 따라 쉽게 조정할 수 있어, 여러 환경에서 유연하게 적용 가능합니다. 또한, Spring은 캐시 스토리지를 Redis, Caffeine, Ehcache 등으로 확장할 수 있어 확장성과 성능 최적화에 큰 도움을 줍니다.
캐시 추상화는 성능 최적화를 위한 중요한 도구로, 특히 반복적으로 조회가 발생하는 서비스에서 큰 효과를 발휘합니다. Spring의 캐시 추상화 기능을 잘 활용하여 애플리케이션의 응답 속도와 자원 활용도를 개선해보세요!
'기술 지식 쌓아가기 📚 > Backend 🍔' 카테고리의 다른 글
[Optimization] Spring의 Ahead-of-Time (AOT) Compilation: 성능과 효율을 높이는 컴파일 방식 알아보기 (0) | 2024.11.10 |
---|---|
[Optimization] 무중단 배포: 서비스 중단 없이 안전하게 배포하는 방법 (0) | 2024.11.09 |
[Optimization] API 부하 테스트란? : nGrinder 활용법 (2) | 2024.11.07 |
[시스템 아키텍처] Observability Support: 시스템 모니터링의 새로운 패러다임 (0) | 2024.10.14 |
[DB] ACID 원칙과 정규화: 데이터베이스 설계의 핵심 원칙 (0) | 2024.10.13 |