본문 바로가기

DevOps/Redis

[Redis] Redis 클러스터, 스프링 부트에서 설정하기- 컴도리돌이

728x90
728x90

Redis 클러스터는 데이터를 여러 노드에 분산 저장하여 확장성과 가용성을 높입니다. 이를 위해 Redis는 키를 해시 슬롯으로 매핑하고, 총 16.384개의 해시 슬롯을 노드들에 분배하죠. 클라이언트는 키의 해시 값에 따라 해당 슬롯을 처리하는 노드를 찾아가는데, 클러스터 재구성이나 노드 장애 시 MOVED 오류가 발생할 수 있어요. 이 경우, 클라이언트는 Redis로부터 새로운 노드 정보를 받고 재요청을 처리하게 됩니다. 

 

Redis 클러스터 설정은 이전 포스팅에서 확인할 수 있습니다. 😆

 

Spring Boot 환경에서 Redis 클러스터를 구성하려면 먼저 application.yml에 클러스터 노드 정보를 설정해야 해요. 

spring:
  redis:
    cluster:
      nodes:
        - {IP}:7001
        - {IP}:7002
        - {IP}:7003
      max-redirects: 3
    timeout: 2000
    lettuce:
      pool:
        max-active: 10
        max-idle: 5
        min-idle: 1

 

여기서 max-redirects는 클라이언트가 MOVED 오류를 처리하며 다른 노드로 리다이렉트 할 최대 횟수를 정의합니다. 너무 낮게 설정하면 클러스터 재구성 후 일부 요청이 실패할 수 있고, 너무 높으면 불필요한 재요청으로 성능 저하를 초래할 수 있어요. 적절한 값을 설정하는 것이 중요합니다. 

 

이제 위 설정을 읽어 Redis 클러스터 연결을 초기화하고, 데이터를 읽고 쓰는 데 필요한 RedisTemplate을 구성합니다.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.util.Arrays;

@Configuration
public class RedisClusterConfig {

    @Bean
	public LettuceConnectionFactory redisConnectionFactory() {
		RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(
				Arrays.asList("192.168.48.12:7001","192.168.48.12:7002","192.168.48.12:7003"));
		clusterConfig.setMaxRedirects(5);
		return new LettuceConnectionFactory(clusterConfig);
	}

	@Bean
	public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new StringRedisSerializer());
		return redisTemplate;
	}
}

 

RedisConnectionFactory는 Redis 서버와의 연결을 설정하며, RedisTemplate은 Redis 작업의 주요 인터페이스입니다. StringRedisSerializer는 키를 문자열로 직렬화하고, GenericJackson2JsonRedisSerializer는 객체를 JSON으로 직렬화합니다.

 

이제는 간단하게 Redis를 실제 애플리케이션에 적용하여 캐싱을 구현하는 방법을 알아볼게요. 사용자 데이터를 캐싱하려면 @Cacheable 애노테이션을 다음과 같이 활용할 수 있습니다. 

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Cacheable(value = "userCache", key = "#userId", unless = "#result == null")
    public String getUserById(String userId) {
        simulateSlowService();
        return "User_" + userId;
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}

 

@Cacheable 어노테이션을 사용해 특정 메서드의 결과를 Redis에 캐싱합니다. 만약 캐시에 데이터가 없다면 메서드가 실행되고, 결과가 캐싱돼요. unless 속성을 통해 null 데이터를 캐싱하지 않도록 제어할 수 있어요. 하지만 Redis에서 캐시를 사용할 때 TTL 설정이 누락되면 메모리 누수가 발생할 수 있습니다. 이를 방지하려면 application.yml에 TTL을 추가해 줍니다. 

spring:
  cache:
    redis:
      time-to-live: 60000

 

Redis를 사용하는 동안 발생할 수 있는 또 다른 문제는 클러스터 노드 장애입니다. 클러스터의 특정 노드가 다운되면 Redis는 자동으로 장애 조치를 수행하고, 새로운 마스터 노드를 선택해요. 이 과정에서 잠시동안 요청이 실패할 수 있으므로, 클라이언트의 타임아웃 설정을 충분히 여유 있게 설정하는 것이 중요해요.

 

이제 실제로 레디스에 데이터가 캐싱되었는지 확인할까요? 다음 명령어를 입력해줍니다. 

redis-cli -c -p 7001

 

정상적으로 캐싱이 되는 것을 확인했습니다. 👍


728x90
728x90