[Project] redis로 성능 개선 하기

이상혁·2024년 11월 14일

Project

목록 보기
10/12

들어가며

이번 포스트에서는 카테고리로 이벤트를 조회하는 api의 성능을 개선을 해보려고 합니다. 예매 프로젝트 특성 상 티켓 예매가 오픈이 되는 날 많은 사용자가 이벤트를 조회를 하는 경우가 발생을 하는데 조회가 느려지면 사용자에게 불편함을 줄 수 있다고 판단을 하였습니다. 성능을 체크를 하고 성능을 개선을 해보고자 합니다.

성능 체크해보기

먼저, 기존의 카테고리로 이벤트를 조회를 하는 api의 코드와 성능을 알아보겠습니다.

public List<EventResponseDTO> getEventByCategoryId(Page<CategoryEventEntity> categoryEventEntities) {
	List<EventResponseDTO> eventEntities = new ArrayList<>();

	categoryEventEntities.forEach(categoryEventEntity -> {
		eventEntities.add(new EventResponseDTO(categoryEventEntity.getEventEntity()));
	});

	return eventEntities;
}

기존의 코드에서는 MySql에 직접 접근을 해서 데이터를 가지고 와서 return을 해주고 있습니다. 즉, getEventByCategoryId메소드가 호출이 될 때마다 DB와 직접 통신을 하면서 데이터를 가지고 오는 것입니다. 그러면 이 코드로 속도가 얼마나 걸리는 지 알아보겠습니다. 테스트는 두 개의 경우를 볼려고 합니다. 하나의 경우는 하나의 요청이 갔을 때와 또 다른 하나는 8000명이 요청을 보냈을 때 입니다.
먼저, 하나의 요청의 대한 속도입니다.

데이터 베이스를 갔다오고 데이터를 넘겨 줬을 때 속도가 49ms가 나왔습니다.
그렇다면, 8000명이 요청을 했다면 얼머나 걸릴까요? 8000명이 점진적으로 요청을 했을 때를 테스트를 해보았습니다.

평균 값이 3172ms가 나왔습니다.
이제 성능을 체크를 해보았으니 성능을 개선을 해보겠습니다.

성능 개선을 위해서 Redis Cache를 선택한 이유

성능 개선을 위해서 Redis Cache를 선택한 이유는 먼저, 현재 프로젝트에서 Redis를 사용을 하고 있습니다. 분산 락을 구현하기 위해서 Redis를 사용을 하고 있습니다. 그래서 Redis Cache를 사용을 한다고 해서 추가적인 비용이나 관리가 필요하지 않습니다.
다음으로는 빠른 속도입니다. Redis는 In-Memory-Database이기 때문에 데이터 베이스까지 접근을 하지 않고 메모리까지만 접근을 하기 때문에 빠르게 데이터를 가지고 올 수 있습니다. 그리고 같은 이유로 데이터 베이스의 부하를 줄여줄 수 있습니다.
또한 카테코리의 의한 이벤트 조회는 자주 조회가 일어나기 때문에 Redis Cache의 저장을 하는 것이 성능 상 더 효율적이라고 판단을 했습니다.

Redis Cache로 성능 개선하기

Redis Cache 설정

 @Bean
 public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());

        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);

        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(7))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(cacheConfig)
                .build();
}

CacheManager는 Spring Boot에서 Redis Cache를 사용할 수 있도록 하는 코드입니다.
ObjectMapper는 JSON의 직렬화와 역직렬화 기능을 제공을 하고 JavaTimeModule은 날짜 타입을 직렬화, 역직렬화를 제공을 하는 클래스입니다. JavaTimeModule의 경우 LocalDate 타입의 필드 값이 있기 때문에 넣어주었습니다. GenericJackson2JsonRedisSerializer는 Redis에 저장할 java 객체를 직렬화 해주는 역할을 합니다. 그래서 객체를 직렬화를 해서 Redis에 JSON 형태로 저장이 됩니다.
RedisCacheConfiguration는 cache의 기본 설정을 설정하는 코드입니다. entryTtl으로 cache의 기간을 7일로 설정을 합니다. serializeKeysWith는 cache의 키의 값을 String 타입으로 직렬화를 하고 serializeValuesWith은 GenericJackson2JsonRedisSerializer를 사용해서 직렬화, 역직렬화를 해줍니다.
마지막으로 Redis 저장소를 연결을 해주고 RedisCacheManager를 생성을 해준다.

Redis Cache 메소드에 적용하기

@Cacheable(value = "events", key = "#categoryEventEntities.content[0].categoryEntity.categoryId")
public List<EventResponseDTO> getEventByCategoryId(Page<CategoryEventEntity> categoryEventEntities) {
	List<EventResponseDTO> eventEntities = new ArrayList<>();

	categoryEventEntities.forEach(categoryEventEntity -> {
		eventEntities.add(new EventResponseDTO(categoryEventEntity.getEventEntity()));
	});

	return eventEntities;
}

Cacheable 어노테이션을 통해서 결과를 Redis Cache에 저장을 할 수 있습니다. 그리고 동일한 메소드가 호출이 되면 Cache에 저장이 된 값이 반환이 됩니다. value는 cache에 저장이 될 이름으로 사용이 되고 key의 경우 cache에 저장이 될 때 key 값으로 사용이 됩니다.

이렇게 Redis Cache을 사용하는 방법에 대해서 알아보았습니다. 그리고 이제 이 Redis Cache를 사용을 했을 때 속도 더 빨라졌는지 확인을 해보도록 하겠습니다.

Redis Cache 성능 확인하기

마찬가지로 요청을 한 번 보낸 것과 여러 명이 요청을 했을 때 속도를 보겠습니다.

요청을 한 번 보냈을 때 결과입니다.
12ms로 기존에 Redis Cache를 사용하지 않았을 때 49ms 보다 37ms 줄어 든 것을 볼 수 있습니다.
확실 더 빨라진 것을 알 수 있습니다.

다음은 8000명이 요청을 했을 때 결과입니다.
평균적으로 878ms으로 Redis Cache를 적용하지 않았던 3172ms 보자 2294ms 줄어든 것을 볼 수 있습니다. Redis Cache를 적용을 한 것이 더 빠르다는 것을 확연하게 알 수 있었습니다.

Redis가 MySql보다 빠른 이유

Redis가 MySql보다 빠른 이유는 In-Memory-Database이기 때문입니다. MySql은 디스크를 사용하기 때문에 Redis보다 더 멀리 있어서 갔다 오는 것이 오래 걸립니다. 또한 Redis의 경우 Key-Value 형태이기 때문에 데이터 구조가 단순해서 접근하기 쉽지만 RDB인 MySql의 경우 테이블이 연결되어 있거나 구조가 복잡하기 때문에 접근을 하려면 시간이 더 걸릴 수 밖에 없습니다.

마무리 &

이번 포스트에서는 Redis Cache를 이용을 해서 경기 조회 api의 성능을 개선을 해보았습니다. 성능을 개선을 한 결과 하나의 요청을 보냈을 때는 37ms의 속도가, 8000명이 했을 때는 2294ms가 개선이 된 것을 볼 수 있었습니다. 1초라는 시간이 어떻게 보면 큰 시간이 아닐 수 있지만 사용자 입장에서는 큰 시간이라고 생각을 합니다. 그런 의미에서 2294ms가 개선이 된 것은 유의미한 개선이었습니다. 그래서 성능을 개선을 할 때 Cache을 잘 적용을 한 다면 유의미한 결과을 얻을 수 있다고 생각이 들었습니다.

profile
꾸준히!

0개의 댓글