개발/Spring

[Spring Cache] Spring boot 환경에서 Redis Cache 사용하기

TutleKing 2023. 2. 15. 00:16

서버를 운영시, 크게 변하지 않는 데이터를 계속 client에서 read 하고자할때, 사용하면 좋은 기능이다.

 

현재 진행중인 프로젝트인 인터넷 서점 구현에서 메인화면에 보이는 상품의 카테고리가 계속 조회가 되는 것 때문에 성능에 영향을 주는 듯하여 spring의 cache 기능을 사용하고자 하였다. 

 

Spring cache는 AOP 기반으로 관심사 분리를 하여 비즈니스 로직에 영향이 없도록 구현이 되어있고,

Redis로 사용시, redis에 관련한 의존성만 추가한다면 편하게 사용할 수 있다.
(현 프로젝트에서는 기존에 ObjectMapper와 Redis에 대한 설정이 되어있어서 더 편하게 사용하였다.)

 

우선 spring boot 2.7.7 환경에서 config 설정은 아래와 같다. 

CachConfig.java

@RequiredArgsConstructor
@EnableCaching
@Configuration
public class CacheConfig {

    private final RedisConnectionFactory redisConnectionFactory;
    private final ObjectMapper objectMapper;

    @Bean
    public CacheManager redisCacheManager() {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .prefixKeysWith("Cache:")
                .entryTtl(Duration.ofMinutes(30))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        springCacheRedisSerializer()));

        return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(
                redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build();
    }

  
    @Bean
    public RedisSerializer<Object> springCacheRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer(objectMapper);
    }

}

 

 

그 후에는 원하는 메서드 혹은 클래스에 @Cachable 과 @CacheEvict를 추가하여 사용하면 된다. 

  • @Cachable : 캐시가 필요한 메서드에 사용할 경우, 해당 리턴 값이 지정한 key 값에 맞춰서 redis에 저장된다. 
  • @CacheEvict : 설정값에 따라서 redis에 저장한 값을 flush 해버린다. 

@Cachable 사용 예제

    ...
    
    // 1번 예제
    @Cacheable(cacheNames = "parentCategories")
    @Transactional(readOnly = true)
    public List<CategoryResponseDto> findParentCategories() {
        return getCategoryResponseDtos(null, Category.DEPTH_PARENT);
    }

    // 2번 예제
    @Cacheable(cacheNames = "childCategories", key = "'parentCategory:'+#parentId")
    @Transactional(readOnly = true)
    public List<CategoryResponseDto> findChildCategoriesByParentId(Long parentId) {
        return getCategoryResponseDtos(parentId, Category.DEPTH_CHILD);
    }


...
  • 1번 예제와 같이 key 값을 지정하지 않았을 경우, 아래 사진과 같이 simpleKey라고 하는 자체적인 key 값을 만들어 redis에 저장한다. 

CacheManager가 자체적으로 generate한 key

  • 2번 예제의 경우 key값을 customizing 하여, 메서드에 입력되는 parentId 값과 함께 key가 저장되도록 하였다. 

key 설정에서 지정한대로 카테고리 id와 함께 잘 들어가있다.

  • cacheNames의 기능은 java 코드 안에서 해당 키를 redis에서 불러오기위해 사용하는 별명과 같다. 
    (key는 실제 redis에서 사용하는 값이고, cachNames는 자바코드에서 개발자가 사용하는 이름 같다)
  • value와 cacheNames의 차이점은 찾지못했다..

@CacheEvict 사용 예제 

@CacheEvict(cacheNames = {"parentCategories", "childCategories"}, allEntries = true)
@RequiredArgsConstructor
@Service
public class CommandCategoryServiceImpl implements CommandCategoryService {
     ...
}
  • 해당 서비스는 Command(생성,수정,삭제)를 진행하기 때문에, 카테고리에 변화가 될 경우 해당하는 캐시의 값을 모두 지우도록 하였다.
  • allEntries가 cachNames로 지정한 데이터만 flush 하는지에 대해 검증이 필요하다.

 

 

참고 spring 공식 문서 

https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-specific-config 

 

Integration

The Spring Framework provides abstractions for the asynchronous execution and scheduling of tasks with the TaskExecutor and TaskScheduler interfaces, respectively. Spring also features implementations of those interfaces that support thread pools or delega

docs.spring.io

 

 

반응형