Spring

[Redis] Spring Boot 연동, 객체 캐싱, MSA에서 사용 시 주의점 Serialize

Karla Ko 2023. 3. 8. 04:28
728x90

개발환경

  • macOS Ventura 13.2
  • Spring Boot 3.0.1 RELEASE
  • JAVA 17

 

1. Build.gradle Dependency 추가

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

2. application.yml 파일 수정

로컬 레디스

spring:
   redis: # Local Redis
      lettuce:
        pool:
           max-active: 10
           max-idle: 10
           min-idle: 2
      port: 6379
      host: 127.0.0.1
      password:

 

쿠버네티스 레디스

spring:
   data: # K8s Redis Custer
     redis:
       cluster:
         nodes:
           - redis-cluster.redis.svc.cluster.local:6379

 

3. RedisConfig 파일 추가

@Configuration
@EnableCaching
public class RedisConfig {


    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;


     @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHost, redisPort));
    }

    @Bean
    public RedisTemplate<String, SendingMsgDTO> redisTemplate() {
        RedisTemplate<String, SendingMsgDTO> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
    
    @Bean
    public CacheManager CacheManager(RedisConnectionFactory cf) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            	.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .entryTtl(Duration.ofMinutes(3L));

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

 

@EnableCaching

Spring에서 @Cacheable과 같은 어노테이션 기반의 캐시 기능을 사용하기 위해서는 먼저 별도의 선언이 필요.

설정 클래스에 추가

 

CacheManager

어노테이션을 추가한 후에는 캐시를 관리해줄 CacheManager를 빈으로 등록해주어야 함

 

entryTtl

3초

 

Serializer

  • GenericJackson2JsonRedisSerializer
  • Jackson2JsonRedisSerializer
  • StringRedisSerializer
1. Serializer
JdkSerializationRedisSerializer
디폴트로 등록되어있는 Serializer이다.

2. StringRedisSerializer
String 값을 정상적으로 읽어서 저장한다.
엔티티나 VO같은 타입은 cast 할 수 없다.
JSON 형태로 직접 encoding, decoding을 해줘야한다.

3. Jackson2JsonRedisSerializer(classType.class)
classType 값을 json 형태로 저장한다.
특정 클래스(classType)에게만 직속되어있다는 단점이 있다.

4. GenericJackson2JsonRedisSerializer
모든 classType을 json 형태로 저장할 수 있는 범용적인 Jackson2JsonRedisSerializer이다.
캐싱에 클래스 타입도 저장된다는 단점이 있다.
RedisTemplate을 이용해 다양한 타입 객체를 캐싱할 때 사용하기에 좋다.
MSA 관점의 프로젝트에서는 사용하지 않는 것이 좋다.

 

4. Cache 파일 추가

Service

@Service
public class SendingCache {

    @Autowired
    private final ReadSendingMsgRepository readSendingMsgRepository;

    ObjectMapper objectMapper = new ObjectMapper();

    // [저장]
    @Cacheable(value = "sendingMsg", key = "#sendingId", cacheManager = "CacheManager")
    public List<String> insertSendingMsgList(Long sendingId,  List<SendingMsgDTO> sendingMsgDTOList) throws JsonProcessingException {
        // 발송 번호(sendingId)에 따른 메세지 DTO 리스트(sendingMsgDTOList)를 redis에 저장

        List<String> list = new ArrayList<>();
        
        sendingMsgDTOList.forEach(sendingMsgDTO -> {
            try {
                String str = objectMapper.writeValueAsString(sendingMsgDTO);
                list.add(str);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        });
        
        return list;
    }



}
@Service
public class SendingCache {

    @Autowired
    private final ReadSendingMsgRepository readSendingMsgRepository;

    ObjectMapper objectMapper = new ObjectMapper();


    @Cacheable(value = "sendingMsg", key = "#sendingId", cacheManager = "CacheManager")
    public List<String> insertSendingMsgList(Long sendingId,  List<SendingMsgDTO> sendingMsgDTOList) throws JsonProcessingException {
        // 발송 번호(sendingId)에 따른 메세지 DTO 리스트(sendingMsgDTOList)를 redis에 저장

        List<String> list = new ArrayList<>();
        
        sendingMsgDTOList.forEach(sendingMsgDTO -> {
            try {
                String str = objectMapper.writeValueAsString(sendingMsgDTO);
                list.add(str);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        });
        
        return list;
    }

}

 

@Cacheable

캐시를 적용할 메소드에 @Cacheable 어노테이션을 붙여주면 캐시에 데이터가 없을 경우에는 기존의 로직을 실행한 후에 캐시에 데이터를 추가하고, 캐시에 데이터가 있으면 캐시의 데이터를 반환

 

ObjectMapper.writeValueAsString

MSA에서 다른 서비스간 Redis 저장 및 조회 하는 경우, 패키지와 클래스 타입에 종속되어 String으로 주고받기 위해 사용

 

 

 

728x90