목차
- WHY — 왜 Redis Cluster가 필요한가
- 핵심 개념 — 샤딩과 해시 슬롯
- Redis Cluster 구성
- 슬롯 라우팅 확인
- Failover 실습
- 과반수 장애 시 클러스터 중단
- 노드 추가 (Scale-out)
- 노드 제거 (Scale-in)
- Sentinel vs Cluster
- 전체 요약
1. WHY — 왜 Redis Cluster가 필요한가
Part 6에서 Sentinel로 HA를 구성했다. Sentinel은 Master 장애 시 자동 Failover를 보장하지만 한계가 있다.
Sentinel 한계
├── Master 1대에 모든 데이터가 쌓임
├── 메모리 한계 도달 시 수평 확장 불가
└── 아리 앱 카드 100만 장, 좋아요 수억 건 → 단일 Master로 감당 불가
Redis Cluster는 데이터를 여러 노드에 분산 저장(샤딩)하여 수평 확장을 가능하게 한다.
2. 핵심 개념 — 샤딩과 해시 슬롯
샤딩(Sharding)이란?
데이터를 여러 노드에 분산 저장하는 것이다.
단일 Master (Sentinel) Redis Cluster
┌─────────────┐ ┌────┐ ┌────┐ ┌────┐
│ 모든 데이터 │ │ P1 │ │ P2 │ │ P3 │
│ Master 1대 │ │33% │ │33% │ │34% │
└─────────────┘ └────┘ └────┘ └────┘
해시 슬롯(Hash Slot)
Redis Cluster는 16384개의 해시 슬롯으로 데이터를 분배한다.
Key → CRC16 해시 → 16384로 나눈 나머지 → 해당 슬롯의 노드로 라우팅
Primary 3개 기준 슬롯 배분
Primary 1 → 슬롯 0 ~ 5460
Primary 2 → 슬롯 5461 ~ 10922
Primary 3 → 슬롯 10923 ~ 16383
개발자는 그냥 set key value만 하면 된다. 어느 노드에 저장되는지는 Redis가 자동으로 처리한다.
수평 확장 가능 범위
Primary 3 → 슬롯 5461개씩
Primary 6 → 슬롯 2730개씩
Primary 12 → 슬롯 1365개씩
Primary 최대 1000개까지 확장 가능
해시 태그 (Hash Tag)
mset, pipeline 등 여러 키를 한 번에 처리할 때 키들이 서로 다른 노드에 있으면 Cross-slot 에러가 발생한다.
{} 안의 값이 같으면 무조건 같은 슬롯 → 같은 노드에 저장되도록 강제할 수 있다.
# Cross-slot 에러 발생 가능
mset ari:card:1 "legendary" ari:card:2 "epic"
# 해시 태그로 같은 슬롯 강제 배치
set {ari:card}:1 "legendary"
set {ari:card}:2 "epic"
# 둘 다 "ari:card" 기준으로 슬롯 계산 → 같은 노드에 저장
아리 앱 카드 10연차 뽑기처럼 여러 데이터를 한 번에 처리할 때 이 패턴이 필요하다.
실무 서버 구성
이상적인 구성
서버 1대 = 노드 1개(짝수대)가 이상적이다.
서버 1 → Primary 1
서버 2 → Primary 2
서버 3 → Primary 3
서버 4 → Replica 1 (Primary 1 백업)
서버 5 → Replica 2 (Primary 2 백업)
서버 6 → Replica 3 (Primary 3 백업)
어느 서버가 죽어도 해당 노드만 영향받고 나머지는 정상 운영된다.
비용 절감 구성
서버 1대에 노드 2개씩 배치하는 타협안이다.
단, Primary와 자신의 Replica는 반드시 다른 서버에 배치해야 한다.
서버 1 → Primary 1 + Replica 2 (Primary 2의 Replica)
서버 2 → Primary 2 + Replica 3 (Primary 3의 Replica)
서버 3 → Primary 3 + Replica 1 (Primary 1의 Replica)
서버1이 죽으면
Primary 1 죽음 → Replica 1(서버3)이 승격 ✅
Replica 2 죽음 → Primary 2의 백업 없음 ⚠️
이 상태에서 서버2까지 죽으면 Primary 2개 장애 → cluster_state:fail이 된다.
3대 구성은 이 리스크를 감수하는 비용 절감 방식이다.
비용이 허락하면 Primay, Replica를 별도 서버에 구성하도록 한다.
Stateful 시스템과 Auto Scaling
Redis Cluster에서 Auto Scaling이 어려운 이유
일반 앱 Auto Scaling (Stateless)
트래픽 증가 → 서버 추가 → 즉시 완료 (수초)
Redis Cluster Scale-out (Stateful)
트래픽 증가 → 노드 추가 → 슬롯 리밸런싱 (데이터 이동, 수분~수시간)
→ 이동 중 네트워크/CPU 부하 발생 → 완료 후 정상화
Redis, MySQL 같은 Stateful 시스템은 데이터가 특정 노드에 묶여있어 즉각적인 Auto Scaling이 위험하다.
실무 대응 방식:
- Self-managed: 트래픽 예측 후 노드 미리 구성, 증설은 새벽 계획된 작업으로 진행
- 관리형 서비스(ElastiCache): 슬롯 리밸런싱 자동 처리
3. Redis Cluster 구성
노드 6개 실행
for i in 1 2 3 4 5 6; do
docker run -d \
--name redis-cluster-$i \
--network redis-cluster-net \
redis:7.2 \
redis-server \
--cluster-enabled yes \
--cluster-config-file nodes.conf \
--cluster-node-timeout 5000 \
--appendonly yes
done
IP 확인
docker ps -q --filter name=redis-cluster | xargs docker inspect \
--format '{{.Name}} {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
/redis-cluster-1 172.18.0.2
/redis-cluster-2 172.18.0.3
/redis-cluster-3 172.18.0.4
/redis-cluster-4 172.18.0.5
/redis-cluster-5 172.18.0.6
/redis-cluster-6 172.18.0.7
클러스터 구성
--cluster-replicas 1 — Primary 1개당 Replica 1개 자동 배정
docker exec -it redis-cluster-1 redis-cli --cluster create \
172.18.0.2:6379 \
172.18.0.3:6379 \
172.18.0.4:6379 \
172.18.0.5:6379 \
172.18.0.6:6379 \
172.18.0.7:6379 \
--cluster-replicas 1
구성 결과
Master[0] → 슬롯 0 ~ 5460 (172.18.0.2) ← Replica: 172.18.0.6
Master[1] → 슬롯 5461 ~ 10922 (172.18.0.3) ← Replica: 172.18.0.7
Master[2] → 슬롯 10923 ~ 16383 (172.18.0.4) ← Replica: 172.18.0.5
[OK] All 16384 slots covered.
클러스터 상태 확인
docker exec -it redis-cluster-1 redis-cli cluster info
cluster_state:ok → 클러스터 정상 동작
cluster_slots_assigned:16384 → 16384개 슬롯 전부 배정
cluster_slots_ok:16384 → 전부 정상
cluster_known_nodes:6 → 6개 노드 인식
cluster_size:3 → Primary 3개
4. 슬롯 라우팅 확인
Cluster 모드에서는 반드시 -c 옵션을 사용해야 한다. 없으면 다른 슬롯의 키 접근 시 에러가 발생한다.
docker exec -it redis-cluster-1 redis-cli -c set ari:card:1 "legendary"
docker exec -it redis-cluster-1 redis-cli -c set ari:card:2 "epic"
docker exec -it redis-cluster-1 redis-cli -c set ari:card:3 "rare"
슬롯 확인
docker exec -it redis-cluster-1 redis-cli cluster keyslot ari:card:1
# 12659 → Master[2] (10923~16383) 담당
docker exec -it redis-cluster-1 redis-cli cluster keyslot ari:card:2
# 272 → Master[0] (0~5460) 담당
docker exec -it redis-cluster-1 redis-cli cluster keyslot ari:card:3
# 4401 → Master[0] (0~5460) 담당
5. Failover 실습
Primary 노드 강제 종료
docker stop redis-cluster-3
Failover 확인 (10초 후)
docker exec -it redis-cluster-1 redis-cli cluster nodes
172.18.0.4 → master,fail ← redis-cluster-3 장애 감지
172.18.0.5 → master ← redis-cluster-4 자동 승격 (slave → master)
slots 10923-16383 인수
데이터 유지 확인
docker exec -it redis-cluster-1 redis-cli -c get ari:card:1
# "legendary" ← 데이터 그대로 유지
6. 과반수 장애 시 클러스터 중단
Redis Cluster는 Primary 과반수가 죽으면 클러스터 전체가 중단된다.
docker stop redis-cluster-1 redis-cluster-2
docker exec -it redis-cluster-4 redis-cli cluster info | grep cluster_state
# cluster_state:fail
docker exec -it redis-cluster-4 redis-cli -c get ari:card:1
# (error) CLUSTERDOWN The cluster is down
복구
docker start redis-cluster-1 redis-cluster-2 redis-cluster-3
docker exec -it redis-cluster-1 redis-cli cluster info | grep cluster_state
# cluster_state:ok
docker exec -it redis-cluster-1 redis-cli -c get ari:card:1
# "legendary" ← 데이터 유지
7. 노드 추가 (Scale-out)
핵심 원칙
클러스터 서비스는 무중단, 노드 관리는 수동
무중단 ✅
├── 슬롯 이동 중에도 클러스터 정상 운영
├── 기존 데이터 접근 가능
└── 클라이언트 자동 리다이렉트
수동 관리 필요 ⚠️
├── reshard로 슬롯 직접 이동
├── add-node / del-node 직접 실행
└── 슬롯 0개 확인 후 노드 제거
슬롯 리밸런싱은 네트워크/CPU 부하가 발생하므로 트래픽이 낮은 새벽에 계획된 작업으로 진행하는 것이 원칙이다.
실습
# 1. 새 노드 실행
docker run -d \
--name redis-cluster-7 \
--network redis-cluster-net \
redis:7.2 \
redis-server \
--cluster-enabled yes \
--cluster-config-file nodes.conf \
--cluster-node-timeout 5000 \
--appendonly yes
# 2. IP 확인
docker inspect redis-cluster-7 \
--format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'
# 172.18.0.8
# 3. 클러스터에 새 노드 추가
# 두 번째 IP는 클러스터 접속 진입점 (클러스터 안의 아무 노드 IP나 가능)
docker exec -it redis-cluster-1 redis-cli --cluster add-node \
172.18.0.8:6379 172.18.0.2:6379
추가 직후 상태 — 슬롯이 없는 master
172.18.0.8 → master, connected (슬롯 없음)
슬롯 리밸런싱
docker exec -it redis-cluster-1 redis-cli --cluster reshard 172.18.0.2:6379
입력값 설명
How many slots do you want to move?
→ 4096
# 16384 ÷ 4 = 4096 (4개 노드 균등 분배 기준)
# 기존 3개 노드에서 각 1365개씩 가져옴
What is the receiving node ID?
→ 새 노드(172.18.0.8)의 ID 입력
# 슬롯을 받을 노드 지정
Source node #1:
→ all 입력
# 기존 모든 노드에서 균등하게 가져옴
# 특정 노드만 지정하려면 해당 노드 ID 입력 후 done
리밸런싱 후 슬롯 배분
Primary 1 → 1365~5460 (4096개)
Primary 2 → 6827~10922 (4096개)
Primary 3 → 12288~16383 (4096개)
Primary 4 → 0~1364 + 5461~6826 + 10923~12287 (4096개, 3개 구간으로 분리 — 정상)
슬롯이 연속적이지 않은 것은 기존 3개 노드에서 균등하게 가져왔기 때문이다.
데이터 유지 확인
docker exec -it redis-cluster-1 redis-cli -c get ari:card:1
# "legendary" ← 슬롯 이동 중에도 데이터 유지
Replica 추가
# 새 Replica 노드 실행
docker run -d \
--name redis-cluster-8 \
--network redis-cluster-net \
redis:7.2 \
redis-server \
--cluster-enabled yes \
--cluster-config-file nodes.conf \
--cluster-node-timeout 5000
# Primary 4의 Replica로 추가
# 노드 ID 확인: redis-cli cluster nodes | grep 172.18.0.8
docker exec -it redis-cluster-1 redis-cli --cluster add-node \
172.18.0.9:6379 172.18.0.2:6379 \
--cluster-slave \
--cluster-master-id <Primary4의노드ID>
8. 노드 제거 (Scale-in)
노드를 그냥 삭제하면 해당 노드의 슬롯이 사라져 데이터 유실이 발생한다.
반드시 Replica 먼저 제거 → 슬롯 이동 → Primary 제거 순서로 진행해야 한다.
실습
# 1. Replica 먼저 제거
docker exec -it redis-cluster-1 redis-cli --cluster del-node \
172.18.0.2:6379 <Replica4의노드ID>
# 2. Primary 4의 슬롯을 다른 노드로 이동
docker exec -it redis-cluster-1 redis-cli --cluster reshard 172.18.0.2:6379
입력값 설명
How many slots do you want to move?
→ 4096 # 제거할 Primary가 가진 슬롯 수
What is the receiving node ID?
→ Primary 1의 ID
# 슬롯을 받을 노드 지정 (균등 분배 원한다면 reshard를 3번 나눠서 진행)
Source node #1:
→ Primary 4의 ID 입력
# 제거할 노드만 소스로 지정
Source node #2:
→ done
# 3. 슬롯 이동 후 자동으로 slave로 강등 확인
docker exec -it redis-cluster-1 redis-cli cluster nodes | grep 172.18.0.8
# 172.18.0.8 → slave (슬롯 0개, 자동 강등)
# 4. Primary 제거
docker exec -it redis-cluster-1 redis-cli --cluster del-node \
172.18.0.2:6379 <Primary4의노드ID>
슬롯이 0개가 되면 Redis Cluster가 자동으로 해당 노드를 slave로 강등시킨다. 이후 del-node로 명시적으로 제거하면 완료된다.
데이터 유지 확인
docker exec -it redis-cluster-1 redis-cli -c get ari:card:1
docker exec -it redis-cluster-1 redis-cli -c get ari:card:2
docker exec -it redis-cluster-1 redis-cli -c get ari:card:3
# "legendary" / "epic" / "rare" ← 노드 추가/제거 전 과정에서 데이터 유실 없음
9. Sentinel vs Cluster 비교
| 구성 | Failover | 샤딩 | 수평확장 | Auto Scaling | 적합한 규모 |
| Master-Replica | 수동 | ❌ | ❌ | ❌ | 개발/스테이징 |
| Sentinel | 자동 ✅ | ❌ | ❌ | Replica만 가능 | 중소규모 |
| Redis Cluster (Self-managed) | 자동 ✅ | ✅ | ✅ | ⚠️ 어려움 | 중대형 |
| ElastiCache Cluster | 자동 ✅ | ✅ | ✅ | ✅ | AWS 등 클라우드 환경 |
10. 전체 요약
Redis Cluster 핵심 원칙
├── 16384개 해시 슬롯을 Primary 수에 맞게 자동 분배
├── 키 → CRC16 → 슬롯 → 노드 라우팅 (자동, 개발자 개입 없음)
├── 해시 태그 {} → 여러 키를 같은 노드에 강제 배치 (mset, pipeline 사용 시)
├── 이상적 구성: 서버 6대 (노드 1개씩)
├── 비용 절감: 서버 3대 (노드 2개씩, 리스크 감수)
├── Primary 과반수 생존 시 클러스터 정상 유지
├── Primary 과반수 장애 시 cluster_state:fail (전체 중단)
├── 노드 추가/제거
│ ├── 클러스터 서비스는 무중단
│ ├── 슬롯 리밸런싱은 수동 (새벽 계획된 작업)
│ ├── 슬롯 0개 시 자동으로 slave 강등
│ └── del-node로 명시적 제거 필요
└── Stateful 특성상 Auto Scaling 대신 용량 계획(Capacity Planning)이 중요
'Infra & Network' 카테고리의 다른 글
| [Kubernetes | Part 2] Redis on Kubernetes (0) | 2026.05.03 |
|---|---|
| [Kubernetes | Part 1] Kubernetes 기초 (0) | 2026.05.01 |
| [Docker | Part 5] Docker 네트워크 원리 이해 (0) | 2026.04.30 |
| [Docker | Part 4] Volume + Network + Registry (0) | 2026.04.30 |
| [Docker | Part 3] Docker Compose (0) | 2026.04.30 |