Redis가 정말 캐싱을 잘 해주는지 아닌지
확인하는 글입니다.
성능을 높이고자 하는 부분
게시물을 불러올때 카테고리를 기준으로 불러오게 됩니다. 매번 카테고리에 관련된 글을 불러올때, 속도를 개선하고자
DB에 직접 쿼리를 날려 조회하는 방식이 아닌, 한번 조회된 데이터는 Redis에 저장해 놓고, 다음번 조회시엔 Redis에서 조회하도록 하는 상황입니다.
Redis관련 설정 코드
package com.sangyunpark.smileboard.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
@Configuration
public class RedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private int port;
@Value("${redis.password}")
private String password;
@Value("${redis.time-to-live}")
private Long expireTime;
@Bean
RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setPort(port);
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPassword(password);
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
return lettuceConnectionFactory;
}
@Bean
RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(expireTime))
.serializeKeysWith(RedisSerializationContext
.SerializationPair
.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(configuration).build();
}
}
코드 분석하기
redisConnectionFactory 메서드
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setPort(port); //
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPassword(password);
RedisStandaloneConfiguration: Redis 서버의 호스트, 포트, 비밀번호 등의 설정을 포함하는 객체이다.
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
return lettuceConnectionFactory;
LettuceConnectionFactory : Spring에서 Redis와의 연결을 관리하기 위한 Lettuce 클라이언트 기반의 커넥션 팩토리이다.
redisCacheManager 메서드
@Bean
RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory, ObjectMapper objectMapper) {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(expireTime))
.serializeKeysWith(RedisSerializationContext
.SerializationPair
.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper)));
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(configuration).build();
}
RedisCacheConfiguration
Redis 캐시에 대한 다양한 설정을 정의하는 객체이다. 이 객체를 통해 캐시의 동작 방식을 세부적으로 조정할 수 있다.
defaultCacheConfig()
Redis 캐시의 기본 설정을 반환한다. 이후 이 설정을 기반으로 추가적인 커스터마이징이 이루어진다.
disableCachingNullValues()
캐시에서 null 값을 캐싱하지 않도록 설정한다. 만약 데이터가 null인 경우 캐시에 저장되지 않는다.
entryTtl(Duration.ofSeconds(expireTime))
캐시에 저장된 데이터의 TTL(Time-To-Live, 만료 시간)을 설정한다. 이 예제에서는 expireTime(초 단위)을 설정하여 캐시 항목이 일정 시간이 지나면 만료되도록 한다.
serializeKeysWith
캐시의 키를 직렬화할 때 사용할 직렬화 방식을 지정한다.
StringRedisSerializer
캐시 키를 문자열로 직렬화하는 데 사용됩니다. 이 직렬화기는 Redis 키를 String 형식으로 처리한다
serializeValuesWith
캐시의 값을 직렬화할 때 사용할 직렬화 방식을 지정한다.
GenericJackson2JsonRedisSerializer
캐시 값을 JSON 형식으로 직렬화하는 데 사용된다. 이 때, ObjectMapper를 사용하여 자바 객체를 JSON으로 변환하고, 다시 역직렬화할 때도 이 설정을 사용한다.
Redis 적용 코드
@Cacheable(value = "getPostsByCategory", key = "'getPostsByCategory' + #category ")
@Transactional
public List<PostDto> getPostsByCategory(final String category) {
Category findCategory = categoryRepository.findByTitle(category).orElseThrow(() -> new NotFoundCategoryException(
CATEGORY_NOT_FOUND));
List<Post> posts = postRepository.findByCategory(findCategory).orElseThrow(() -> new NotFoundPostException(POST_NOT_FOUND));
List<PostDto> postDtos = posts.stream().map(post -> PostDto.fromEntity(post)).collect(Collectors.toList());
return postDtos;
}
@Cacheable어노테이션을 사용해서 카테고리를 기준으로 게시물을 조회할때, 지정해둔 key값과 value값으로 redis에 데이터를 저장해준다.
@Cacheable의 동작 순서
- 메서드가 실행되고, 그 결과는 캐시에 저장
- 동일한 입력 값으로 다시 호출되면, 메서드를 실행하지 않고, 캐시에서 저장된 값을 반환
- 동일한 입력 값으로 다시 호출될때, 캐시에 값이 없을 경우, 메서드를 실행하고 그 결과를 캐시에 저장
성능 결과 확인
[로컬 환경에서의 비교]
Redis를 사용하지 않은 경우의 조회 - 첫 조회
실행 속도 : 84ms
Redis를 사용한 경우의 조회 - 두번 연속 조회
실행 속도 : 10ms
🙆🏻♂️ 약 74ms의 응답속도가 줄어들었다!
'Redis' 카테고리의 다른 글
Redis SortedSet 정말 빠른가? (0) | 2024.10.17 |
---|