Redis-cluster 구성 (feat. Spring)

sooni·2024년 4월 22일
0

#1. Redis

Redis 설치 (Windows)

Windows에서 redis 다운로드 받기 MS 공식 github에서 2016년 버전이 끝이다.
최대한 최근 버전이 필요해서 서치하던 중 링크 에서 새로운 윈도우 버전을 다운로드 받을 수 있다.

msi 로 설치 > C:Program Files/Redis 폴더에서 Redis가 설치된 것을 확인할 수 있다.

Cluster 구성

가장 기본으로 설치되는 포트 6379이 아닌 최소 구성 조건인 master node 3개 127.0.0.1:7000, 127.0.0.1:7001, 127.0.0.1:7002 로 구성한다.

각 노드 폴더 생성

# C:Program Files/Redis
$ mkdir 7000
$ mkdir 7001
$ mkdir 7002

conf file 생성

C:Program Files/Redis/redis.7000.conf, redis.7001.conf, redis.7002.conf 생성
각 포트에 맞게 아래 conf file 내용 변경 필요

port 7000
daemonize yes
logfile ./7000/log_7000.txt
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
dir ./7000

redis 실행

$ redis-server redis.7000.conf
$ redis-server redis.7001.conf
$ redis-server redis.7002.conf

cluster 시작

$ redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 --cluster-replicas 1

cluster info 확인

$ redis-cli -c -p 7000
127.0.0.1:7000> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3
cluster_size:3
cluster_current_epoch:3
cluster_my_epoch:1
cluster_stats_messages_ping_sent:3847
cluster_stats_messages_pong_sent:3855
cluster_stats_messages_sent:7702
cluster_stats_messages_ping_received:3853
cluster_stats_messages_pong_received:3847
cluster_stats_messages_meet_received:2
cluster_stats_messages_received:7702

추가) service 로 관리

service 등록해서 사용

등록 및 실행

$ cd Redis # redis 위치하는 폴더
$ redis-server --service-install redis.7000.conf --service-name redis7000
$ redis-server --service-install redis.7001.conf --service-name redis7001
$ redis-server --service-install redis.7002.conf --service-name redis7002

$ redis-server --service-start --service-name redis7000
[19584] 29 Apr 11:28:09.104 # Redis service successfully started.
$ redis-server --service-start --service-name redis7001
[13072] 29 Apr 11:28:13.634 # Redis service successfully started.
$ redis-server --service-start --service-name redis7002
[20996] 29 Apr 11:28:17.145 # Redis service successfully started.

종료 및 해지

$ redis-server --service-stop --service-name redis7000
$ redis-server --service-stop --service-name redis7001
$ redis-server --service-stop --service-name redis7002

$ redis-server --service-uninstall --service-name redis7000
$ redis-server --service-uninstall --service-name redis7001
$ redis-server --service-uninstall --service-name redis7002

#2. Spring

Redis 설정

주의⭐ node 주소는 현재 ip 그대로 적으면 오류날 수 도 있다. (127.0.0.1:7000 으로 적어보기)

RedisConfig.java

@EnableCaching
@Configuration
@RequiredArgsConstructor
@Slf4j
public class RedisConfig implements CachingConfigurer {
    private final AppProperties appProperties;

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        Set<String> nodes = new HashSet<>();
        for (String node : appProperties.getRedisClusterNodes()) {
            try {
                nodes.add(node.trim());
            } catch (RuntimeException ex) {
                throw new IllegalStateException("Invalid redis sentinel property nodes {} : {}" + node, ex);
            }
        }

        RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(nodes);
        clusterConfiguration.setMaxRedirects(5);
        LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
                .commandTimeout(Duration.ofMinutes(1))
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(clusterConfiguration,clientConfiguration);
    }

    private ObjectMapper objectMapper() {
        PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator
                .builder()
                .allowIfSubType(Object.class)
                .build();

        return new ObjectMapper()
                .findAndRegisterModules()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false)
                .registerModule(new JavaTimeModule())
                .activateDefaultTyping(ptv, ObjectMapper.DefaultTyping.NON_FINAL);
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate() {
        final RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer(objectMapper()));
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(RedisSerializer.java());
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }


    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
                .disableCachingNullValues()
                .computePrefixWith(cacheName -> "prefix::" + cacheName + "::")
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        new GenericJackson2JsonRedisSerializer(objectMapper())
                ));
    }

    @Override
    @Bean
    public CacheManager cacheManager() {
        return RedisCacheManager.builder(this.redisConnectionFactory())
                .cacheDefaults(this.cacheConfiguration())
                .build();
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                log.warn(exception.getMessage(), exception);
            }

            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                log.warn(exception.getMessage(), exception);
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                log.warn(exception.getMessage(), exception);
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                log.warn(exception.getMessage(), exception);
            }
        };
    }
}

Service 구현

@Service
@Slf4j
@RequiredArgsConstructor
public class TestService {

	@Cacheable(value="CACHE_NAME", key="#testType")
    public String getTestType(TestType testType) {
        return testMapper.selectTestType(testType); // testTypeResult
    }
}

redis 저장 확인

$ redis-cli -c -p 7000
127.0.0.1:7000> get prefix::CACHE_NAME::testType # cacheConfiguration perfix 확인
testTypeResult #저장된값

참고

0개의 댓글