Java

[Redis] 직렬화

연신내고독한늑대 2024. 8. 26. 20:00

 

# Redis에서의 기본 직렬화 설정

Spring에서 RedisTemplate을 사용할 때, 직렬화 설정을 명시적으로 하지 않으면, 기본적으로 Redis는 JdkSerializationRedisSerializer를 사용합니다. 이 직렬화기는 Java의 직렬화 메커니즘을 활용하여 객체를 바이트 스트림으로 변환합니다.

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 기본적으로 직렬화 설정이 없는 경우 JdkSerializationRedisSerializer가 사용됩니다.
        return template;
    }
}

위 코드에서 StringRedisSerializer를 명시적으로 설정하지 않으면, 키와 값 모두 JdkSerializationRedisSerializer
를 사용하게 됩니다.

 

# JdkSerializationRedisSerializer의 문제점

JdkSerializationRedisSerializer는 Java 객체를 직렬화하고 이를 바이트 배열로 변환하여 저장합니다. 하지만 이 방식에는 몇 가지 중요한 단점이 있습니다:

  1. 호환성 문제: Java 직렬화된 객체는 다른 언어 또는 다른 시스템과의 호환성이 부족합니다. 이는 Redis가 여러 시스템 간의 데이터 교환을 처리할 때 문제가 될 수 있습니다.
  2. 데이터 가독성: 직렬화된 데이터가 바이트 배열로 저장되기 때문에, Redis 클라이언트를 통해 데이터를 직접 확인하기 어렵습니다. 문자열처럼 읽을 수 있는 데이터가 아닙니다.
  3. Redis 키 문제: 기본적으로 키도 JdkSerializationRedisSerializer에 의해 직렬화되므로, 키가 복잡한 바이트 배열로 저장될 수 있습니다. 이는 데이터 검색 시 예기치 않은 동작을 초래할 수 있습니다.

 

# @Cacheable과 StringRedisSerializer 사용의 중요성

@Cacheable 어노테이션은 메소드의 결과를 캐시에 저장하고, 이후 동일한 메소드 호출이 있을 경우 캐시에서 데이터를 반환하도록 합니다. 예를 들어, 다음과 같이 @Cacheable을 사용한다고 가정해봅시다:

@Cacheable(value = "userCache", key = "#userId")
public User getUserById(String userId) {
    // 데이터베이스 또는 다른 서비스 호출
}

만약 StringRedisSerializer를 사용하지 않고 기본 설정을 유지한다면, Redis에 저장되는 키와 값은 모두 JdkSerializationRedisSerializer를 통해 직렬화됩니다. 이 경우, 키(userId)는 복잡한 바이트 배열로 직렬화되어 저장됩니다.

문제는, Redis에서 키를 검색할 때 @Cacheable 어노테이션이 단순한 문자열을 키로 사용하려고 시도하지만, Redis에 저장된 키는 직렬화된 바이트 배열이므로 일치하지 않게 됩니다. 결과적으로, 캐시에서 데이터를 찾지 못하고 항상 "데이터가 없는" 상태로 메소드가 실행됩니다.

 

# 해결 방법: StringRedisSerializer 사용

이 문제를 해결하기 위해 StringRedisSerializer를 사용하여 키를 직렬화하는 것이 좋습니다. 아래 코드를 통해 Redis에 저장되는 키를 문자열로 직렬화할 수 있습니다

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 키를 문자열로 직렬화
        template.setKeySerializer(new StringRedisSerializer()); 
        // 값을 Java 직렬화로 유지할 수도 있습니다.
        template.setValueSerializer(new JdkSerializationRedisSerializer());
       
        return template;
    }
}

이렇게 설정하면, @Cacheable에서 사용하는 키(userId)가 Redis에 문자열로 저장되고, 이후 검색할 때도 동일한 형식으로 비교가 이루어져 정상적으로 캐시된 데이터를 찾을 수 있습니다.

 

# 결론

Redis에서 Spring을 사용할 때 직렬화 설정은 매우 중요합니다. 기본적으로 사용되는 JdkSerializationRedisSerializer는 호환성 문제와 가독성 문제를 일으킬 수 있으며, @Cacheable과 같은 기능이 의도한 대로 동작하지 않을 수 있습니다. 이를 방지하기 위해 StringRedisSerializer를 사용하여 키를 명확하게 문자열로 직렬화하는 것이 좋습니다. 이를 통해 Redis에 저장되는 데이터가 예상대로 동작하고, 캐시에서 데이터를 정확하게 조회할 수 있습니다.