Redis를 활용한 Spring Boot 캐싱 처리: 성능과 고가용성을 동시에 잡는 법
1. 서론: 왜 Redis 캐시를 사용해야 할까?
사용자가 늘어남에 따라 데이터베이스(DB) 서버는 병목 지점이 됩니다. 매번 동일한 데이터를 DB에서 가져오는 대신, 메모리 기반의 고성능 저장소인 Redis에 보관해두면 어떨까요?
Redis는 초당 수만 건의 읽기/쓰기를 처리할 수 있어, 잦은 조회 작업이 발생하는 API 성능 개선에 탁월합니다. 이번 포스팅에서는 실무 사례를 바탕으로 Redis 캐시 적용법을 살펴보겠습니다.
2. Spring Boot Redis 설정과 구현
먼저, Spring Boot에서 Redis 라이브러리를 추가하고 캐시 매니저를 설정해야 합니다.
Maven 의존성 추가 및 설정 예시
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 캐시 유효 시간: 10분
.serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
3. 실무 사례: 인기 상품 상세 페이지 캐싱
상황: 하루 수십만 명이 접속하는 커머스 사이트에서, 베스트셀러 상품 상세 정보를 조회하는 쿼리가 DB에 과부하를 주고 있습니다.
캐시 적용 로직 (Look-aside 패턴)
@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
@Cacheable(value = "products", key = "#id", unless = "#result == null")
public ProductDto getProductDetail(Long id) {
log.info("DB에서 상품 정보를 조회합니다. (id: " + id + ")");
return productRepository.findById(id)
.map(ProductDto::from)
.orElse(null);
}
@CacheEvict(value = "products", key = "#id")
public void updateProduct(Long id, ProductUpdateDto updateDto) {
// 상품 정보 수정 시 캐시 삭제 (Cache-aside 패턴의 핵심)
productRepository.update(id, updateDto);
}
}
이 코드를 적용하면 첫 번째 조회 시에만 DB에 접근하고, 이후 10분간은 Redis에서 데이터를 가져오므로 DB 부하가 90% 이상 줄어듭니다.
4. Redis 캐시 운영 시 주의사항 (Critical Tips)
- 데이터 일관성(Inconsistency): DB의 데이터가 바뀌었을 때 캐시도 즉시 삭제하거나 업데이트해야 합니다.
@CacheEvict를 적절히 활용하세요. - 캐시 유효 시간(TTL) 설정: 무한정 캐시를 쌓아두면 Redis 메모리가 부족해집니다. 데이터의 중요도에 따라 적절한 TTL(예: 1분, 10분, 1시간)을 설정해야 합니다.
- 직렬화 문제: Redis에 저장할 객체는 반드시
Serializable을 구현하거나, JSON 형식으로 직렬화 설정을 해줘야 나중에 다른 서버에서도 읽을 수 있습니다.
5. 결론: “캐시"는 선택이 아닌 필수입니다.
사용자의 트래픽이 몰리는 지점(Hotspot)을 찾아 적절히 Redis 캐시를 적용하는 것만으로도, 고가의 DB 장비를 증설하는 것보다 수십 배 높은 비용 효율을 낼 수 있습니다.
다음 포스팅에서는 이 서비스를 안정적으로 배포하기 위한 Docker 컨테이너화 전략에 대해 다뤄보겠습니다.