gony-dev 님의 블로그

[Redis] Connection Mode-2 본문

DBMS

[Redis] Connection Mode-2

minarinamu 2024. 12. 8. 12:48

2024.12.06 - [DBMS] - [Redis] Connection Mode-1

이전 글에서 Connection Mode의 다음 모드들을 알아보았다.
1. Redis Standalone(default)
2. Master/Slave
3. Redis Sentinel

이번 포스트에서는 미처 다루지 못한 Redis Cluster를 알아보고,
모드들의 조합들이 어떤 이점을 취하는지 알아보자!

 

1. Redis Cluster

  • Redis Cluster는 RedisConnection의 확장이라고 생각하면 된다.
  • 대규모 데이터 처리를 위한 "수평적 확장"을 사용하며, 데이터를 여러 노드에 분산 저장하는 역할을 한다.
  • 노드 간 자동 복제를 통해 데이터 안정성을 유지시키고, 일부 노드 장애 시에도 데이터 접근이 가능하다.
  • 이전 포스트에서 다루었던 2개 이상의 마스터/슬레이브 아키텍쳐로 구성되어 있다.

application.yml

spring:
	data:
        redis:
            password: ${PASSWORD}
            cluster:
                max-redirects: ${MAX_REDIRECTS}
                nodes:
					${NODE1_IP}:${NODE1_PORT},
					${NODE2_IP}:${NODE2_PORT}

 

RedisProperty.class

@Getter
@Setter
@NoArgsConstructor
@ConfigurationProperties(prefix = "spring.data.redis")
@Configuration
public class RedisProperty {

    private String password;
    private int maxRedirects;
    private List<String> nodes;
}

 

RedisConfig.class

@Bean
public LettuceConnectionFactory redisConnectionFactory() {

    private final List<String> nodes = redisProperty.getNodes();
    private final String password = redisProperty.getPassword();
    private final int maxRedirects = redisProperty.getMaxRedirects();     
    private final List<RedisNode> redisNodes = nodes.stream()
		.map(node -> new RedisNode(node.split(":")[0], Integer.parseInt(node.split(":")[1])))
		.toList();
		
    RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
    clusterConfiguration.setClusterNodes(redisNodes);
    clusterConfiguration.setMaxRedirects(maxRedirects);
    clusterConfig.setPassword(password);
        
    SocketOptions socketOptions = SocketOptions.builder()
		.connectTimeout(Duration.ofMillis(100L))
		.keepAlive(true)
		.build();

    ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
            .dynamicRefreshSources(true)
            .enableAllAdaptiveRefreshTriggers()
            .enablePeriodicRefresh(Duration.ofMinutes(30L))
        .build();

    ClientOptions clientOptions = ClusterClientOptions.builder()
       	    .topologyRefreshOptions(clusterTopologyRefreshOptions)
    	    .socketOptions(socketOptions)
        .build();

    LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
        	.clientOptions(clientOptions)
    	    .commandTimeout(Duration.ofMillis(3000L))
        .build();

    return new LettuceConnectionFactory(clusterConfiguration, clientConfiguration);
}
  • 원래는 Cluster에 대한 기본 설정만 하려고 했으나, 참고한 블로그에 유용한 추가 설정이 있어 따라 기입해보았다!
  1. SocketOptions
    • Redis 인스턴스와 통신하기 위해 클라이언트 라이브러리인 Lettuce가 Socket을 활용한다.
    • connectTimeout | 소켓 연결 시 초과 시간을 설정한다. 해당 초과 시간이 지날 시 조치를 취해 연쇄 장애를 막는다.
    • keepAlive | keepAlive 옵션을 alive로 설정하면, 어플리케이션 중 실패한 연결을 처리해야 할 상황이 줄어든다.
      또한 TCP Connection이 활성화된 상태를 유지하며 ACK를 계속해서 수신하여 ACK가 주어진 시간 내에 오지 않으면 끊어진 것으로 간주하여 종료된다.
  2. ClusterTopologyRefreshOptions
    • Redis Cluster는 3개 이상의 노드들로 구성이 되어 있기에 노드에 대한 변경 작업이 발생할 시 topology가 변경된다.
      이 때, 최신 redis 클러스터 정보를 동기화하여 갱신을 제어하기 위한 설정을 제공한다.
    • dynamicRefreshSources | 클러스터의 동적 소스 갱신을 활성화하며, 클러스터 노드 갱신 시에 새로운 노드가 자동으로 추가되며, 삭제된 노드는 목록에서 제거된다.
      기본적으로 대규모 redis 클러스터는 false를 설정하여, redis 클라이언트가 seed 노드과 상호작용하여 새로운 노드를 찾는다.
    • enableAllAdaptiveRefreshTriggers | redis 클러스터에서 발생하는 이벤트를 클라이언트 어플리케이션이 수신하여 topology를 갱신한다.
    • enablePeriodicRefresh | 일정 시간마다 Cluster topology를 업데이트한다. 비활성화 시, 명령을 실행하고 오류가 발생할 때에만 업데이트 된다. 너무 짧지 않게 설정하도록 유의하자!
  3. ClientOptions
    • 클라이언트에 대해 설정했던 SocketOptions와 ClusterTopologyRefreshOptions를 반영한다.
    • 이외에도 자동 재접속을 시도하는 "autoReconnect()"와 ping 명령어를 사용하여 커넥션 연결 가능 여부를 확인하는 "pingBeforActivateConnection()" 등이 있다.
  4. Lettuce Client
    • 최종적으로 LettuceClient에 반영하는 설정들을 모두 넣어준다.
    • commandTimeout | 지연 연결을 사용하기에 타임아웃을 설정하며 commandTimeout이 ConnectionTimeout보다 커야 함을 알아두자!
  • 위의 SocketOptions나 ClientOptions는 Cluster를 설정하지 않을 때에도 효율적인 측면에서 설정해두면 좋으니 기억하자!

조합하여 사용하기

Redis의 모드를 조합하여 사용하면, 다음과 같은 이점을 챙길 수 있다.

  1. 마스터/슬레이브 + Sentinel
    • 읽기 부하가 많은 경우 문제 해결
    • 마스터 장애 시 슬레이브를 승격시켜 장애 복구
  2. Redis Cluster + Sentinel
    • 클러스터에 더해 더 강력한 장애 복구 기능을 추가할 때 사용
    • 각 클러스터 노드 내에서 마스터/슬레이브를 구성
    • Sentinel은 클러스터 외부에 배치되어 장애 복구 가능

❗️Redis Cluster와 Sentinel 조합은 지양❗️

둘은 본래 다른 목적으로 설계되었기에 일반적으로 같이 사용하지 않는 것이 좋다.

그 이유는 다음과 같다.

  • Cluster는 수평 확장이 목적이 반면, Sentinel은 마스터/슬레이브에 대한 관리를 담당.
  • Sentinel은 데이터 샤딩이 불가능
  • Redis Cluster는 내장된 장애 복구 기능이 있기에 Sentinel 사용 시 중복됨.

만일 둘을 결합하여 사용하길 원한다면, 다음과 같은 구조를 구현하자.

  1. 다중 클러스터
    • 여러 Redis Cluster를 설정하고, 각 클러스터를 독립적으로 운영하며 Sentinel을 사용하여 클러스터 간 고가용성을 설정.
  2. 클라이언트 로드밸런싱
    • 클라이언트 수준에서 Sentinel을 활용하여 여러 Redis 클러스터 중 하나로 라우팅 되도록 설정.

결론

무턱대로 항상 Cluster를 사용하는 것만이 좋은 것도 아니고, 마스터/슬레이브가 무조건적으로 좋은 것도 아니다.

실무에 따라 어떤 것이 비용, 가용성 측면에서 적합한지 고려하고 사용하자!

 


출처

https://velog.io/@komment/Spring-Boot-Redis-Cluster-with-lettuce-redisson

'DBMS' 카테고리의 다른 글

[Redis] Connection Mode-1  (0) 2024.12.06
[Redis] Spring batch vs. Scheduler  (0) 2024.10.17
[Redis] Transaction  (0) 2024.10.15