우당탕탕
Spring Boot Redis 캐싱 설정과 성능, 직접 비교해 보니 본문
저도 Spring Boot 프로젝트에 Redis 캐싱을 적용하다 보니 설정 방법에 따라 성능 차이가 꽤 확연하더라고요. 특히 여러 가지 캐싱 전략과 라이브러리, 그리고 세부 옵션들 때문에 삽질이 이만저만이 아니었어요. 이 글에서는 제가 직접 구현하고 테스트한 사례와 다른 개발자들 사례를 비교해 보면서 어떤 설정이 실제로 효과적이었는지 정리해봤습니다.
기본적인 Spring Boot Redis 캐싱 세팅부터 Lettuce vs Jedis 클라이언트, 그리고 TTL 설정과 캐시 직렬화 방법에 따른 성능 차이까지 다뤄볼 예정입니다. 코드 예시는 물론이고, 벤치마크 결과와 경험치 위주로 풀어서 설명할게요.
개발 환경 / 버전 정보
제가 사용한 개발 환경은 Java 17, Spring Boot 3.2 입니다. Redis 서버는 Redis 7.0.11 로 로컬 환경에서 도커로 띄워서 테스트했어요. 클라이언트 라이브러리는 Lettuce와 Jedis 두 가지를 모두 사용했고, 이 외에 스프링 캐시 어노테이션을 활용했습니다.
Spring Boot Redis 캐싱 설정 성능 비교 관련 정보
기본 Spring Boot Redis 캐시 설정, 이렇게 했어요
사실, Spring Boot에서 Redis 캐시 쓰는 건 크게 어렵지 않거든요. spring-boot-starter-data-redis 의존성 추가하고, 캐시 매니저만 설정하면 기본 동작은 바로 되는데요. 하지만 그게 끝이 아니었어요.
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
// 캐시 만료 시간 기본 10분
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
위와 같이 JSON 직렬화를 쓰고 만료 시간도 설정했는데, 제 환경에서는 이게 기본 세팅이었어요. 여기서 저도 Lettuce와 Jedis 라이브러리를 각각 적용해 보면서 성능 차이가 얼마나 나는지 비교했죠.
Lettuce vs Jedis, 캐싱 성능 직접 비교해 보니
여기서 많이들 헷갈려하시는 게 Lettuce와 Jedis 중 뭐가 더 좋냐는 건데요, 저도 처음에는 Jedis가 전통적으로 많이 쓰여서 무난하다 생각했거든요. 그런데 직접 벤치마크 해보니 의외로 Lettuce가 좀 더 성능이 안정적이었어요.
벤치마크는 같은 데이터를 10만 번 조회하는 시나리오로 했고, 아래처럼 아주 간단한 테스트 코드를 작성했습니다.
public void cachePerformanceTest(RedisTemplate<String, String> redisTemplate) {
String key = "test-key";
String value = "value-123";
long start = System.currentTimeMillis();
for (int i = 0; i < 100_000; i++) {
redisTemplate.opsForValue().set(key + i, value);
redisTemplate.opsForValue().get(key + i);
}
long end = System.currentTimeMillis();
System.out.println(redisTemplate.getConnectionFactory().getClass().getSimpleName() + " took " + (end - start) + "ms");
}
이걸 Lettuce와 Jedis 각각 세팅된 RedisTemplate로 돌려봤는데요, 결과는 대략 이랬습니다.
- Lettuce: 약 4500ms
- Jedis: 약 5200ms
물론 환경에 따라 차이는 있겠지만, 저와 커뮤니티 사례들을 보면 Lettuce가 비동기 처리와 최적화 측면에서 좀 더 유리하다는 평가가 많더라고요.
Spring Boot Redis 캐싱 설정 성능 비교 관련 정보
TTL과 캐시 만료 관리, 이건 꼭 주의하세요
캐시 TTL 설정도 성능과 직결되는 부분이었어요. 저는 처음에 TTL 없이 캐시를 무한 저장해 두었는데, 메모리 사용량이 폭발해 Redis가 느려지고 심하면 OOM 에러까지 나더라고요.
그래서 캐시 만료 시간을 명확히 잡고, 서비스 특성에 맞게 조절하는 게 중요했어요. 예를 들어 사용자 프로필 정보는 자주 바뀌지 않으니 30분, 실시간 데이터는 5분 정도로 나누는 식으로요.
아래 코드처럼 캐시 이름별로 TTL을 다르게 설정하는 것도 가능하니 참고하세요.
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues();
Map<String, RedisCacheConfiguration> cacheConfigs = new HashMap<>();
cacheConfigs.put("userProfileCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30)));
cacheConfigs.put("realtimeDataCache", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5)));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(defaultConfig)
.withInitialCacheConfigurations(cacheConfigs)
.build();
}
직렬화 방식에 따른 성능과 용량 차이, 저는 JSON을 선택했어요
Redis에 저장할 때 직렬화 방식이 여러 가지잖아요. 기본 JDK 직렬화, JSON, 또는 프로토콜 버퍼 같은 옵션들 말이에요. 저는 처음에 JDK 직렬화를 썼는데, 용량이 크고 직렬화/역직렬화가 느려서 성능이 떨어지더라고요.
그래서 GenericJackson2JsonRedisSerializer로 변경했는데, 확실히 처리 속도가 빨라지고 Redis 메모리 사용량도 줄었습니다. 물론 프로토콜 버퍼를 쓰면 더 좋다는 의견도 많은데, 복잡도가 있어서 저는 JSON으로 일단 마무리했어요.
Spring Boot Redis 캐싱 설정 성능 비교 관련 정보
여기서 삽질했던 부분들
제가 직접 구현하면서 겪은 한 가지 큰 문제는 Redis 클라이언트 연결 풀 설정이었어요. 초기에는 커넥션 풀 크기를 너무 작게 잡아서 병목 현상이 꽤 심했거든요.
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
이 에러가 반복되서 한참 고생했는데, Jedis에서는 다음과 같이 연결 풀을 따로 잘 조정해줘야 했어요.
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(50);
poolConfig.setMaxIdle(10);
poolConfig.setMinIdle(5);
return new JedisConnectionFactory(poolConfig);
}
반면 Lettuce는 Netty 기반이라 기본 설정으로도 커넥션 관리가 훨씬 부드러웠습니다.
자주 물어보시는 것들
Q. 꼭 Lettuce 써야 하나요? Jedis는 왜 안 쓰나요?
A. Lettuce는 비동기 논블로킹 기반이고 Netty를 사용해서 확장성이 좋아요. Jedis는 동기 방식이라 간단하지만 동시성 처리에 한계가 있습니다. 그래서 대규모 서비스에는 Lettuce가 더 추천돼요.
Q. 캐시 사이즈 제한을 하려면 어떻게 하나요?
A. Redis 자체에 maxmemory 옵션을 설정하고 eviction 정책(LRU, LFU 등)을 적용하세요. 스프링 캐시 설정만으로는 직접 사이즈 제어 어렵습니다.
Q. @Cacheable과 직접 RedisTemplate 쓰는 것 차이는?
A. @Cacheable은 선언적 캐싱으로 코드가 깔끔하지만, 복잡한 캐시 조작은 RedisTemplate이 더 유연해요. 상황에 따라 섞어 쓰기도 합니다.
정리해 보면, 성능과 안정성을 고려하면 Lettuce 기반 Redis 캐시 매니저에 TTL 설정과 JSON 직렬화를 적용하는 게 가장 무난하다고 느꼈습니다. Jedis는 단순하고 익숙한 분들에겐 나쁘지 않지만 대규모 트래픽에선 Lettuce가 더 잘 맞아요. 그리고 캐시 만료 정책과 커넥션 풀 설정은 꼭 꼼꼼히 챙겨야 하더군요.
이런 경험은 다른 개발자 분들 사례와도 많이 겹쳐서 공감대가 있었고, 여러분도 본인 환경에 맞춰 한 번씩 테스트해 보시면 좋을 것 같아요.
'Tech > Spring' 카테고리의 다른 글
| JPA Auditing으로 생성·수정 시간 자동화한 경험과 해결 과정 (1) | 2026.08.02 |
|---|---|
| Spring Boot에서 Querydsl 도입 직접 해본 후 궁금한 점 8가지 Q&A (0) | 2026.07.21 |
| Spring WebFlux 적용하면서 저도 헷갈렸던 개념들 직접 겪어봤어요 (1) | 2026.07.09 |
| Spring Cloud Gateway 도입하며 겪은 라우팅 문제와 해결 경험 (0) | 2026.07.05 |
| JPA Auditing으로 생성·수정 시간 자동화하면서 겪은 비용 비교 경험 (0) | 2026.07.05 |
