우당탕탕
Redis 캐싱 Spring Boot 연동 직접 구현해보니 경험한 모든 과정 본문
제가 직접 Redis 캐싱을 Spring Boot에 연동해보면서 생각보다 삽질했던 부분들이 많았어요. 데이터베이스 쿼리 최적화를 위해 캐시를 도입했는데, 이 과정에서 설정부터 실제 코드 작성, 테스트까지 모든 단계를 하나씩 기록해봤습니다.
이 글에서는 Redis 캐시를 Spring Boot 프로젝트에 연동하는 절차, 캐시 적용 후 쿼리 성능 변화, 그리고 주의할 점까지 실제 경험을 중심으로 단계별로 안내할게요. 저처럼 직접 구현하는 동안 참고가 되셨으면 해요.
개발 환경 / 버전 정보
우선 제가 사용한 환경부터 공유드릴게요. Java 17, Spring Boot 3.1.4 버전 기준입니다. Redis는 Redis 7.0 로 로컬에 설치했어요.
또한 의존성은 spring-boot-starter-data-redis 와 lettuce 클라이언트를 추가했습니다.
Redis 캐싱 Spring Boot 연동 직접 구현해보니 관련 정보
Redis 설치 및 실행 세팅
사실 이 부분이 처음이라 제일 막혔는데, 저는 로컬 Mac 환경에서 Homebrew를 이용해서 Redis를 설치했고 바로 실행했어요.
- 터미널에서
brew install redis입력 후 설치 - 설치 완료 후
redis-server명령어로 데몬 실행 - 다른 터미널 창에서
redis-cli ping테스트해 PONG 응답 확인
Redis가 백그라운드에서 잘 돌아가는지 확인했으니 Spring Boot와 연동할 차례였어요.
Spring Boot 프로젝트에 Redis 의존성 추가
저는 build.gradle 에 다음 의존성을 넣었어요.
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'io.lettuce:lettuce-core:6.2.1.RELEASE'
설치한 Redis 버전과 Lettuce 클라이언트 버전 호환도 꼭 챙겨야 하는데, Lettuce가 Spring Data Redis 기본 클라이언트라 무난했어요.
application.properties 세팅
Redis와 연결하기 위해 application.properties 에 기본 설정을 추가했어요.
spring.redis.host=localhost
spring.redis.port=6379
포트나 호스트를 바꿔야 할 환경이라면 맞춰서 수정하면 됩니다.
Redis 캐싱 Spring Boot 연동 직접 구현해보니 관련 정보
Redis 캐시 활성화 및 설정 클래스 작성
사실 이 부분에서 헷갈리는 분들이 많은데, 저는 Spring Boot 애플리케이션 클래스에 @EnableCaching 어노테이션을 추가해서 캐시 기능을 켰어요.
그리고 Redis 캐시 전략을 위해 아래처럼 RedisCacheManager를 빈으로 등록했습니다.
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig())
.build();
}
}
이렇게 하면 Spring이 자동으로 캐시된 데이터를 Redis에 저장하고 관리하게 됩니다.
서비스 메서드에 캐시 적용
많이들 헷갈려하는 게 바로 여기에요. 저는 데이터베이스에서 조회하는 메서드 위에 @Cacheable 을 붙여서 캐시 기능을 적용했어요.
간단한 예를 들면, 아래처럼 특정 사용자 정보를 DB에서 가져오는 메서드에 캐시를 씌웠습니다.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Cacheable(value = "userCache", key = "#userId")
public User getUserById(Long userId) {
try {
Thread.sleep(1000); // 느린 DB 쿼리 시뮬레이션
} catch (InterruptedException e) {
e.printStackTrace();
}
return userRepository.findById(userId).orElse(null);
}
}
직접 써보니 캐시가 잘 작동하면 처음 호출할 땐 DB 조회가 느리지만, 이후 호출부터는 바로 Redis에서 데이터를 가져와 쾌적하게 응답되더라고요.
실제 쿼리 성능 테스트 및 결과
이 부분이 저는 가장 신기했는데요, 아래 결과처럼 캐시 적용 전후 쿼리 시간을 측정해봤어요.
- 첫 실행(캐시 미적용): 약 1,000ms 걸림 (DB 직접 조회)
- 두 번째 실행(캐시 적용): 5~10ms (Redis에서 바로 조회)
이 차이 덕분에 실제 사용자 요청 처리 속도가 확실히 빨라지는 걸 체감할 수 있었어요.
Redis 캐싱 Spring Boot 연동 직접 구현해보니 관련 정보
여기서 삽질했던 부분들
제가 가장 오래 헤맸던 부분은 캐시가 적용되지 않아 계속 DB를 조회하는 문제였어요. 원인은 캐시 키 설정이 맞지 않아서였는데요.
@Cacheable(value = "userCache", key = "#user.id") // 틀린 경우
public User getUserById(Long userId) { ... }
사실 #user.id로 지정하면 안 되고, 메서드 인자 이름과 맞춰서 #userId 로 작성해야 캐시가 올바르게 작동하더라고요.
또 Redis가 실행되어 있지 않으면 예외가 나는데, 이런 점도 실행 전에 꼭 확인해야 해요.
심화: 캐시 만료 시간 설정도 중요해요
제가 실제 서비스를 돌려보니 무조건 캐시가 영구적이면 데이터가 오래된 상태로 남아 문제가 돼서 만료 정책도 설정했어요. 아래처럼 캐시 기본 설정을 바꿨죠.
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 10분 후 만료
.disableCachingNullValues();
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(cacheConfig)
.build();
}
이렇게 하면 10분이 지나면 캐시가 자동 삭제되고, 최신 DB 데이터를 다시 조회해서 캐시를 갱신해줘서 데이터 신선도를 유지할 수 있었어요.
자주 물어보시는 것들
Q. Redis 없이도 캐시가 가능한가요?
A. 로컬 메모리 캐시도 있지만, 분산 환경이라면 Redis 같은 외부 캐시를 쓰는 게 안정적이고 확장성 면에서 훨씬 좋습니다.
Q. 캐시 적용 시 데이터 정합성 문제는 어떻게 해결하나요?
A. 캐시 만료 시간과, 데이터 변경 시 명시적으로 캐시 삭제(@CacheEvict)를 적용하는 걸 추천합니다.
저도 이렇게 하나씩 적용하면서 캐시가 제대로 작동하는 걸 확인했고, 데이터베이스 쿼리 부하를 눈에 띄게 줄여서 만족스러웠어요.
'Database' 카테고리의 다른 글
| MySQL EXPLAIN 실행 계획에서 확인할 주요 항목 (0) | 2026.10.17 |
|---|---|
| MySQL 8.4에서 SKIP LOCKED 사용 시 조건과 한계 (0) | 2026.10.16 |
| MySQL 트랜잭션 격리수준, 제가 실수했던 사례와 FAQ 정리 (0) | 2026.10.13 |
| MySQL 트랜잭션 격리수준 세팅하며 제가 한 실수와 해결법 (0) | 2026.09.05 |
| Redis pub/sub 메시지 큐로 써본 후, 자주 묻는 질문 8가지 (0) | 2026.09.04 |