Redis Cluster가 제공하는 것
- 여러 노드에 자동적인 데이터 분산
- 일부 노드의 실패나 통신 단절에도 계속 작동하는 가용성
- 고성능을 보장하면서 선형 확장성을 제공
Redis Cluster 특징
1. Partitioning(파티셔닝)
- 16384개의 해시 슬롯을 사용하여 데이터를 파티셔닝합니다.
- 키의 해시 값에 따라 특정 슬롯에 할당됩니다.(CRC16 해시 함수를 사용)
- 각 Redis 노드는 16384개의 해시 슬롯 중 일부를 책임집니다.
- 클라이언트는 키의 해시 슬롯을 계산하여 해당 데이터를 저장하거나 검색할 Redis 노드를 알 수 있습니다.
1) CRC16 해시 함수
CRC16은 키를 16비트의 정수 값으로 변환하는데 0 ~ 65535 까지의 범위를 가질 수 있습니다.
2) 해시 슬롯
Redis Cluster는 16384개의 해시 슬롯을 사용합니다.
따라서, 각 키의 CRC16 해시 결과는 16384로 나누어 해당 키가 어떤 해시 슬롯에 속하는지를 결정합니다.해시 슬롯번호 = CRC16(키) %(mod) 16384
ex) CRC 해시 함수의 결과가 20000인 키는 20000 %(mod) 16384 = 3616
으로 해시 슬롯 3616에 할당됩니다.
3) 키의 할당
각 Redis 노드는 16384개의 해시 슬롯 중 일부를 책임지게 됩니다.
따라서, 특정 키가 어떤 해시 슬롯에 할당되는지를 알면, 그 키를 저장하거나 조회해야 할 Redis 노드를 알 수 있습니다.
4) 키의 재할당
노드가 추가되거나 제거될 때, 해시 슬롯의 할당이 재조정될 수 있습니다.
이는 노드 간의 데이터 이동을 초래하지만, Redis Cluster는 이러한 재조정 과정을 자동으로 관리합니다.
5) 태그를 이용한 해싱
Redis Cluster에서는 여러 키가 동일한 해시 슬롯에 할당되도록 키 이름에 태그를 사용할 수 있습니다.
태그는 키 이름에서 중괄호 '{}'로 둘러싸인 부분입니다.
ex) user:{123}:name
및 user:{123}:age
는 동일한 해시 슬롯에 할당됩니다.
2. 고가용성
- 각 마스터 노드는 하나 이상의 슬레이브 노드를 가질 수 있습니다.
- 마스터 노드에 장애가 발생하면, 해당 마스터의 슬레이브 중 하나가 새로운 마스터로 승격됩니다.
- 이를 통해 네트워크 파티션, 장애, 재구성 시에도 서비스 중단 없이 동작을 계속할 수 있습니다.
1) Redis Cluster의 고가용성 동작
- 마스터와 슬레이브 노드
Redis Cluster에서 각 마스터 노드는 여러 슬레이브 노드를 가질 수 있습니다.
슬레이브 노드는 마스터 노드의 데이터 복제본을 유지하며, 마스터 노드에 장애가 발생할 경우 대체 노드로서의 역할을 합니다.
- 노드 감지
Redis Cluster 노드들은 서로를 주기적으로 확인(Ping 방식, Gossip 프로토콜)하며, 노드의 상태 정보를 교환합니다.
만약 마스터 노드가 응답하지 않는다면, 그 노드는 실패로 간주됩니다.
- 슬레이브 승격
마스터 노드가 실패하면, 그 마스터의 슬레이브 중 하나가 새로운 마스터로 승격됩니다.
승격은 여러 요인을 기반으로 결정되는데, 데이터 복제의 지연 시간, 노드의 ID, 연결 상태 등이 고려됩니다.
2) 슬레이브의 마스터 승격 과정
- 장애 인식
다른 노드들은 주기적인 Ping 메시지를 통해 노드의 상태를 감지합니다.
만약, 마스터 노드가 일정 시간 동안 응답하지 않으면, 그 노드는 실패로 판단됩니다.
- 승격 대기
슬레이브 노드들은 일정시간(기본 15초) 동안 기다린 후 자신을 마스터로 승격시키기 시작합니다.
기다리는 시간은node-timeout
값에 의해 조절됩니다.
- 승격 결정
가장 최근에 마스터 노드로부터 데이터를 복제받은 노드, 해당 조건이 동일한 경우 노드 ID가 낮은 노드가 마스터 노드로 승격됩니다.
3) 클라이언트의 동작
- 서버 연결
클라이언트는 일반적으로 모든 Redis Cluster 노드에 대한 정보를 갖고 있지 않을 수 있습니다.
- MOVED 오류 처리
클라이언트가 연결된 노드에 데이터를 요청하면, 그 노드가 요청된 데이터를 가지고 있지 않은 경우 "MOVED" 오류와 함께 올바른 노드의 주소를 반환합니다.
클라이언트는 이 주소로 재 연결하여 요청을 다시 시도합니다.
- 노드 정보 업데이트
클라이언트는 Redis Cluster 내의 노드 상태와 위치 정보를 주기적으로 업데이트하여 최신 상태를 유지합니다.
3. 데이터 복구와 장애 복구
- 마스터 노드가 실패하면 슬레이브 노드 중 하나가 자동으로 마스터로 승격됩니다.
- Redis Cluster의 장애 복구 기능은 네트워크 분할을 포함한 다양한 시나리오에 대응할 수 있습니다.
4. 클라이언트와의 통신
- 클라이언트는 모든 Redis 노드에 연결하지 않아도 됩니다.
- 클라이언트가 연결된 노드가 요청한 키를 갖고 있지 않은 경우, 클라이언트는 "MOVED" 오류 메시지를 받게 됩니다.
- 이 메시지는 올바른 노드의 주소와 함께 제공되므로, 클라이언트는 해당 주소로 재연결하여 요청을 수행 할 수 있습니다.
MOVED 오류 처리 방식
- MOVED 메시지 읽기
클라이언트는 'MOVED' 메시지를 읽어 특정 키에 대한 올바른 노드의 주소를 파악합니다.
'MOVED' 메시지는 보통 다음과 같은 형태입니다.MOVED hash_slot ip:port
- 내부 매핑 업데이트
클라이언트는 자체적으로 클러스터 노드와 해시 슬롯에 대한 매핑을 유지합니다.
'MOVED' 메시지를 받으면, 클라이언트는 이 매핑 정보를 업데이트해 올바른 노드에 키를 매핑합니다.
- 재요청
클라이언트는 'MOVED' 메시지에서 얻은 새로운 주소로 요청을 다시 전송합니다.
* 예시) Springboot에서 Lettuce를 이용한 방법
- 의존성 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
- application.yml 추가
# application.yml
spring:
redis:
cluster:
nodes:
- node1host:port
- node2host:port
- Service 생성
package com.example.rediscluster;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class RedisService {
private final StringRedisTemplate stringRedisTemplate;
@Autowired
public RedisService(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public void set(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}
- Controller 생성
package com.example.rediscluster;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisController {
private final RedisService redisService;
@Autowired
public RedisController(RedisService redisService) {
this.redisService = redisService;
}
@GetMapping("/set")
public String set(@RequestParam String key, @RequestParam String value) {
redisService.set(key, value);
return "Value set successfully!";
}
@GetMapping("/get")
public String get(@RequestParam String key) {
return redisService.get(key);
}
}
5. 안정성 및 한계점
- Redis Cluster는 마스터 노드가 과반 수 이상 문제가 생긴다면 어떤 노드도 쓰기 작업을 수락하지 않습니다.
- 일부 Redis 기능들, 예를 들면 multi-key operations는 클러스터 모드에서 제한될 수 있습니다. Redis Cluster는 해시슬롯 기반으로 노드에 분할되어 있기 때문입니다. 따라서, 모든 키가 같은 노드에 있는 경우 multi-key가 동작합니다.
6. 클러스터 재구성
- Redis Cluster는 노드 장애를 감지하고 자동으로 클러스터를 재구성하는 메커니즘을 가지고 있습니다.
'개발 > 대용량트래픽' 카테고리의 다른 글
Hexagonal Architecture 완전 가이드: Ports와 Adapters로 구현하기 (0) | 2024.01.25 |
---|---|
Redis와 Gossip 프로토콜: 빠른 네트워크 상태 동기화 기술 (0) | 2024.01.25 |
Redis Sentinel의 이해: 고가용성을 위한 모니터링 및 장애 조치 전략 (1) | 2024.01.25 |
Redis ZSet의 이해: 스코어 기반 정렬의 모든 것 (0) | 2024.01.25 |
싱글 스레드의 이해와 Redis의 고급 관리 전략 (1) | 2024.01.25 |
댓글