작성
·
53
·
수정됨
0
간단한 영화 목록 조회입니다. 총 약 10000개의 데이터가 있습니다. redis를 적용하고 조회성능이 좋아진것은 맞지만 이상하게 redis를 적용하기 전에도 같은 조회를 계속해도 조회속도가 똑같이 빨라지는 현상을 겪고있습니다. 현재 이 movie는 MSA 의 여러 서비스 중 하나입니다. 혹시 MSA 아키텍쳐 자체가 문제가 될 수도 있나요?
@Cacheable(cacheNames = "getMovies", key = "'movie:all'",
cacheManager = "movieCacheManager")
public List<Movie> getAllMovies() {
return movieRepository.findAll();
}
@GetMapping("/movies")
public ResponseEntity<List<MovieDto>> getAllMovies() {
List<Movie> allMovies = movieService.getAllMovies();
List<MovieDto> dtos = new ArrayList<>();
for (Movie movie : allMovies) {
dtos.add(new ModelMapper().map(movie, MovieDto.class));
}
return ResponseEntity.status(HttpStatus.OK).body(dtos);
}
@Configuration
@EnableCaching // Spring Boot의 캐싱 설정을 활성화
public class RedisCacheConfig {
@Bean
public CacheManager movieCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
// Redis에 Key를 저장할 때 String으로 직렬화(변환)해서 저장
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
// Redis에 Value를 저장할 때 Json으로 직렬화(변환)해서 저장
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()
)
)
// 데이터의 만료기간(TTL) 설정(1분)
.entryTtl(Duration.ofMinutes(1L));
return RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
}
}
답변 3
0
안녕하세요 ! 질문 잘 해주셨어요 !
질문해 주신 내용에 대해 상황을 기반으로 하나씩 정리해서 답변드려 볼게요 !
[1] JPA 자체의 1차 캐시(영속성 컨텍스트) 때문일 가능성
우선 가장 유력한 원인이라고 생각됩니다 !
"movieRepository.findAll()이 반복 호출임에도 DB 부하 없이 빠른 이유"
Spring Data JPA는 기본적으로 영속성 컨텍스트(EntityManager)가 존재하며,
트랜잭션 안에서 같은 데이터를 여러 번 조회할 경우 DB를 다시 조회하지 않고
1차 캐시에 보관된 엔티티를 반환해요~
즉, Redis를 사용하지 않아도 같은 요청이 계속 반복된다면,
이미 JPA가 빠른 결과를 리턴해줬던 것일 수 있어요!
[2] 너무 많은 10,000개 영화 데이터를 한번에 캐싱
@Cacheable은 조회 결과 전체를 메모리에 캐싱해요 ~
10,000개 Movie 객체를 JSON 직렬화하여 저장/읽기하는 건 Redis I/O 비용이 크며,
이걸 네트워크 통해 주고받는 것도 성능 이슈가 될 수 있어요!
즉, 무작정 큰 데이터를 한 번에 캐싱하는 건 오히려 역효과가 발생할수 있어요 !
"MSA 아키텍처 자체가 원인이 될 수 있을까요?"
-> 직접적인 원인은 아니라고 생각해요 ~
위 두 부분을 확인한뒤 해당 사항을 고려해보는 것을 추천드려요 !
추가로 궁금한 사항 있으시면 언제든 질문 남겨주세요~~ 😄
0
안녕하세요, 인프런 AI 인턴입니다. 이수현님께서 Redis 적용 후 성능 저하와 관련하여 질문을 주셨네요. 캐시 적용 후 성능이 개선되지 않는 원인은 여러 가지가 있을 수 있습니다. 몇 가지 가능한 원인과 해결 방안을 제안드리겠습니다.
Redis에 캐시된 데이터가 없는 경우, 캐시 미스로 인해 DB에 다시 접근하여 데이터를 가져오는 데 시간이 소비됩니다. 처음 한 번은 캐시 미스가 발생할 수 있지만, 그 이후로는 캐시에 데이터가 저장되어야 합니다. 실제로 후속 요청에서도 성능 문제가 유지되는지 확인해보세요.
애플리케이션 서버와 Redis 서버 간에 네트워크 딜레이가 있으면 성능 저하를 유발할 수 있습니다. 같은 네트워크 환경에서 테스트하거나 네트워크 속도를 측정해볼 필요가 있습니다.
GenericJackson2JsonRedisSerializer
를 사용하셨는데, 데이터 변환 과정에서 성능에 영향을 미칠 수 있습니다. Jackson2JsonRedisSerializer
로 변경해서 테스트를 시도해보세요.처음부터 모든 데이터를 캐시에 로드하는 방식(findAll()
)은 대량의 데이터를 불러오면서 성능 저하를 발생시킬 수 있습니다. 페이징을 통해 데이터를 부분적으로 로드하는 방법을 고려해 볼 수 있습니다.
아래 유사 질문에서 해결의 실마리를 찾으실 수도 있습니다:
- 캐싱 객체 직렬화/역직렬화
이해에 도움이 되셨기를 바랍니다. 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
0
추가적인 Movie와 MovieDto 코드입니다.
@Data
public class MovieDto {
private Long id;
private String title;
private String genre;
private Integer runningTime;
private String descreption;
private String director;
@JsonFormat(pattern = "yyyy-MM-dd")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate releaseDate;
}
@Data
@Entity
public class Movie {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String genre;
private Integer runningTime;
private String descreption;
private String director;
@JsonFormat(pattern = "yyyy-MM-dd")
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate releaseDate;
}
먼저 일단 문제는 해결되었습니다! 10000건의 데이터를 100만개의 데이터로 개수를 늘렸고 조회를 100만개를 다 하는것이 아니라 페이징을 적용했더니 큰 차이가 있었습니다. 실제로 Redis 적용전 475ms -> 90ms였는데 Redis 적용 후 600ms->9ms로 큰 성능을 맛볼 수 있었습니다. 감사합니다!