개발 기록

>[Redis] Spring Boot 3 Redis Sentinel 환경 구성 및 구현 - 2. Spring Redis Sentinel config 본문

SQL&NoSQL

>[Redis] Spring Boot 3 Redis Sentinel 환경 구성 및 구현 - 2. Spring Redis Sentinel config

1z 2024. 1. 9. 13:59

 

 

개발환경

java 17
spring version 6.0.11 (4.x-5.x)
spring boot version 3.1.3 (1.x-2.x)

 

 

1. 설정 

 

(1) Redis 의존성 추가 

spring-boot-starter-data-redis: Spring Data Redis 및 Lettuce 클라이언트와 함께 Redis 키-값 데이터 저장소를 사용하기 위한 Starter.

spring-boot-starter-cache : Spring Framework의 캐싱 지원을 위한 스타터로, 캐싱 공급자와 작업할 때 사용하는 주석을 제공.

 

(2) Application.yml

default => host: localhost, port: 6379

 

 

(3) RedisConfig.java

1) annotation

1. @EnableCaching : 캐싱을 활성화하기 위해 사용한다. (활성화시 @Cacheable, @CacheEvict 등의 어노테이션이 사용 가능)

2. @EnableRedisRepository : RedisRepository 활성화

@Slf4j
@Configuration
@EnableCaching
@EnableRedisRepositories 
@RequiredArgsConstructor
public class RedisConfig implements CachingConfigurer {

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

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

    @Value("${spring.data.redis.timeout}")
    private Duration redisCommandTimeout;

    @Value("${spring.cache.redis.time-to-live}")
    private long redisTimeToLive;

    @Value("${spring.data.redis.password}")
    private String password;

    private final RedisProperties redisProperties;


    // RedisConnectionFactory를 통해 내장 혹은 외부의 Redis를 연결
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {

        // 레디스 센티넬 서버들 설정
        RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
            .master(redisProperties.getSentinel().getMaster())
            .sentinel("localhost",5000)
            .sentinel("localhost",5001)
            .sentinel("localhost",5002);

        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
        		// 레디스 명령어를 실행하고 응답받는 시간 설정
                .commandTimeout(redisCommandTimeout)
                // 데이터 조회 시 데이터를 어떤 노드에서 조회할지 설정
                // (REPLICA_PREFERRED : REPLICA 우선, 조회 불가능시 MASTER에서 조회)
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();
        return new LettuceConnectionFactory(sentinelConfig, clientConfig);
    }



    // Redis 캐시에서 저장하고 가져올 때 키와 값의 직렬화/역직렬화가 수행되는 방식을 정의
    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }


    // 캐시구성
    @Bean
    @Override
    public RedisCacheManager cacheManager() {
        // RedisCacheManagerBuilder:  null 값, 키 접두사 및 바이너리 직렬화를 포함하여 캐시별로 캐싱 동작을 더욱 세부적으로 조정
        return RedisCacheManager
            .builder(this.redisConnectionFactory())
            .cacheDefaults(this.cacheConfiguration())
            .build();
    }


    /**
     * Spring Boot 가 기본적으로 RedisCacheManager 를 자동 설정해줘서 RedisCacheConfiguration 없어도 사용 가능
     * Bean 을 새로 선언하면 직접 설정한 RedisCacheConfiguration 이 적용됨
     */
    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        // Serializer 변경 (default : JdkSerializationRedisSerializer => Json 데이터를 직렬화하여 Redis에 저장이 가능한 형태로 변경을 할 수 없다.
        // 캐싱할 API의 응답값 데이터 타입이 String 타입이 아니면 Serializer 에러가 발생하므로
        // 직렬화 가능한 Jackson2JsonRedisSerializer 또는 GenericJackson2JsonRedisSerializer로 변경을 합니다.
        return RedisCacheConfiguration.defaultCacheConfig()
            .prefixCacheNameWith("test_") // prefix
            .entryTtl(Duration.ofMinutes(redisTimeToLive))  // 캐시 수명 30분
            .disableCachingNullValues() // 캐싱할 때 null 값을 허용하지 않음 (#result == null 과 함께 사용해야 함)
            // StringRedisSerializer: binary 데이터로 저장되기 때문에 이를 String 으로 변환시켜주며(반대로도 가능) UTF-8 인코딩 방식을 사용한다.
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
    }
    

    @Override
    public CacheErrorHandler errorHandler() {
        return new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                log.info("Failure getting from cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                log.info("Failure putting into cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                log.info("Failure evicting from cache: " + cache.getName() + ", exception: " + exception.toString());
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                log.info("Failure clearing cache: " + cache.getName() + ", exception: " + exception.toString());
            }
        };
    }

}

 

 

 

 

2) 설정상세

1. RedisProperties  : application.yml 에 정의한 접두사로 매핑하고 해당 값을 가져온다.  LettuceConnectionFactory를 생성하여 bean으로 등록

 

2. Redis Cache 적용을 위해 RedisCacheManager를 설정한다  Redis Sentinel 연결로 캐시 관리자를 초기화하고 아래 캐시 구성 빈을 사용하여 캐시 구성을 제공한다. 

public RedisCacheManager cacheManager() 

 

2. RedisSentinelConfiguration 설정 : redis 서버와 연결할 수 있는 ConnectionFactory 를 생성한다.

public RedisConnectionFactory redisConnectionFactory()

 

3. RedisSerializer 바이너리 저장소 형식과의 변환을 위한 키 만료 시간, key와 value의 직렬화 방식,접두사 및 구현을 설정

: 위 설정에서는 StringRedisSerializer 를 사용하여 문자열로 된 키를 직렬화하고, GenericJackson2JsonRedisSerializer 를 사용하여 일반적인 객체를 JSON 형식으로 직렬화했다.

* 속성 

☞  prefixCacheNameWith: Cache Key prefix 설정
☞  entryTtl: 캐시 만료 시간
☞  disableCachingNullValues: 캐싱할 때 null 값을 허용하지 않음 (#result == null 과 함께 사용해야 함)
☞  serializeKeysWith: Key 를 직렬화할 때 사용하는 규칙. 보통은 String 형태로 저장
☞  serializeValuesWith: Value 를 직렬화할 때 사용하는 규칙. 

public RedisCacheConfiguration cacheConfiguration()

 

3-1. 만약 캐시이름 별로 여러 세팅을 하고 싶다면 RedisCacheManagerBuilderCustomizer 를 선언해서 사용하면 된다.

 

4. errorHandler  : Redis 명령 실행 중에 발생한 예외를 처리하기 위해 사용자 정의 오류 핸들러를 정의

 

 

 

(4) Class 설명

RedisConnetioin 레디스 통신에 있어서 building block 을 제공하여 레디스 백엔드에서의 통신
RedisStandlaloneConfiguration Replication 구조로 구성된 레디스 서버에 연결 설정  
RedisSentinelConfiguration Sentinel 구조로 구성된 레디스 서버에 연결 설정
RedisClusterConfiguration Clusert 구조로 구성된 레디스 서버에 연결 설정  
RedisSocketConfiguration
유닉스 소켓을 이용하여 구성과 동일한 호스트에 게스트 레디스 서버에 연결을 사용할 때 사용
RedisConnetioinFactory 활성화된 RedisConnection들은 RedisConnectionFactory을 통해서 생성
RedisCacheConfiguretion  
RedisCacheManagerBuilder  
RedisCaheManagerCustomizer  
LettuceClientConfiguration  
CacheManager  

 

 

(5) 직렬화

1. GenericJackson2JsonRedisSerializer: 객체를 json타입으로 직렬화/역직렬화를 수행한다. 모든 classType을 json 형태로 저장 가능

캐싱에 클래스 타입도 저장된다는 단점이 있지만 RedisTemplate을 이용해 다양한 타입 객체를 캐싱할 때 사용하기에 좋다

* 주의할 점은 여러개의 데이터를 한번에 저장할 때 List 를 사용하지 말고 별도의 일급 컬렉션을 선언해서 사용해야 한다.

2. StringRedisSerializer: String을 byte[]로 직렬화하고 또는 byte[]를 String으로 역직렬화 한다. UTF-8 인코딩 방식을 사용한다.

3. JdkSerializationRedisSerializer :  디폴트로 등록되어있는 Serializer이다.

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

 

https://loosie.tistory.com/807#2._RedisTemplate_(low_level)

 

 

 

 

 




 

 

참고

https://bcp0109.tistory.com/

https://arahansa.github.io/docs_spring/redis.html

https://mycup.tistory.com/282

https://medium.com/javarevisited/caching-with-spring-boot-3-lettuce-and-redis-sentinel-5f6fab7e58f8

https://assu10.github.io/dev/2023/09/24/springboot-redis-1/