💾 "메모리가 부족해지면 어떻게 하나요?"
서비스가 성장하면서 Redis에 저장해야 할 데이터가 늘어납니다. 처음에는 서버 메모리를 늘리면(Scale-Up) 됩니다. 하지만 한 대 서버의 메모리에는 한계가 있습니다. 그때는 서버를 여러 대로 늘리는(Scale-Out) 방법이 필요합니다.
Redis Cluster는 데이터를 여러 노드에 나눠서 저장하는 공식 분산 솔루션입니다. 각 노드는 전체 데이터의 일부만 담당하고, 클라이언트는 어떤 노드에 요청해도 올바른 노드로 자동 리다이렉트됩니다.
Cluster는 Sentinel과 다릅니다. Sentinel은 "한 대가 죽으면 다른 한 대가 대신"하는 고가용성(HA)이고, Cluster는 "데이터를 여러 대에 나눠 저장"하는 수평 확장(Scale-Out)입니다. 물론 Cluster도 각 샤드마다 Replica를 두어 HA를 함께 구성합니다.
🎰 핵심 개념 1: 16,384 해시 슬롯
Redis Cluster는 전체 키 공간을 16,384개의 슬롯으로 나눕니다. 모든 키는 CRC16 알고리즘으로 해시값을 계산한 뒤 16,384로 나눈 나머지로 슬롯 번호가 결정됩니다.
slot = CRC16(key) % 16384예: "user:1000" → CRC16 계산 → 12345 % 16384 = 12345번 슬롯
3개 Primary 노드라면 슬롯이 균등 분배됩니다:
노드A: 0~5460, 노드B: 5461~10922, 노드C: 10923~16383
클라이언트가 어떤 노드에 요청을 보내든, 그 노드가 해당 키의 슬롯을 담당하지 않으면 MOVED 리다이렉트 응답을 보냅니다. 클라이언트는 이를 받아 올바른 노드로 재요청합니다. redis-cli -c 옵션을 쓰면 이 리다이렉트가 자동으로 처리됩니다.
🏷️ 핵심 개념 2: 해시 태그 — 같은 슬롯 강제
Cluster에서는 여러 키를 한 번에 처리하는 멀티키 명령(MGET, MSET, SUNIONSTORE 등)이 제한됩니다. 관련된 키들이 서로 다른 노드에 있을 수 있기 때문이죠.
이를 해결하는 것이 해시 태그(Hash Tag)입니다. 키 이름에서 {} 안의 내용만으로 슬롯을 계산합니다. 같은 태그를 쓰면 관련 키들이 같은 슬롯(같은 노드)에 저장됩니다.
# 해시 태그 없이: 다른 슬롯에 저장될 수 있음
SET order:1000:item "coffee" # 슬롯 A
SET order:1000:status "pending" # 슬롯 B (다른 노드!)
# MGET 오류 발생 가능
MGET order:1000:item order:1000:status
# → CROSSSLOT Keys in request don't hash to the same slot
# 해시 태그 사용: 같은 슬롯 강제
SET order:{1000}:item "coffee" # CRC16("1000") % 16384
SET order:{1000}:status "pending" # 동일 슬롯!
# 이제 MGET 가능
MGET order:{1000}:item order:{1000}:status
# → 1) "coffee" 2) "pending"
🔬 Lab 10: 6노드 클러스터 생성
Redis Cluster 최소 구성은 3개의 Primary + 각각 1개의 Replica = 총 6개 노드입니다. Primary 3개인 이유는 Cluster도 다수결로 장애를 판단하기 때문입니다.
# 각 노드별 디렉토리와 설정 파일 생성
for port in 7000 7001 7002 7003 7004 7005; do
mkdir -p ./cluster/$port
cat > ./cluster/$port/redis.conf << EOF
port $port
cluster-enabled yes
cluster-config-file nodes-$port.conf
cluster-node-timeout 5000
appendonly yes
dir ./cluster/$port
EOF
done
# 6개 노드 실행
for port in 7000 7001 7002 7003 7004 7005; do
redis-server ./cluster/$port/redis.conf &
done
# 클러스터 생성 (--cluster-replicas 1 = 각 Primary마다 1개의 Replica)
redis-cli --cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
# 슬롯 분배 확인 후 yes 입력
# -c 옵션: 클러스터 모드 (MOVED 자동 리다이렉트)
redis-cli -c -p 7000
# 클러스터 정보
CLUSTER INFO
# cluster_state: ok
# cluster_slots_assigned: 16384
# 슬롯 배분 확인
CLUSTER NODES
# 각 노드의 슬롯 범위 확인
# 키 저장 (자동 리다이렉트)
SET user:1 "alice"
# → Redirected to slot [10485] located at 127.0.0.1:7002
# → OK
# 해시 태그 테스트
SET order:{1000}:item "coffee"
SET order:{1000}:status "pending"
MGET order:{1000}:item order:{1000}:status # 성공!
⚠️ 실전 팁: Sentinel vs Cluster 선택 기준
| 기준 | Sentinel 추천 | Cluster 추천 |
|---|---|---|
| 목적 | 고가용성(장애 복구) | 수평 확장(메모리 부족) |
| 단일 노드 메모리 한계 | 문제 없음 | 한계 도달 시 |
| 멀티키 명령 필요 | 자유롭게 사용 가능 | 해시 태그 필요 (제약 있음) |
| 운영 복잡도 | 낮음 | 높음 |
| 최소 노드 수 | 3 (Sentinel) + 2 (Redis) | 6 (3Primary + 3Replica) |
| 데이터 양 | 수십 GB 이하 | 수십 GB 초과 시 |
🚨 Cluster의 제약사항
멀티키 명령 제한: 서로 다른 슬롯의 키를 한 번에 조작하는 MGET, MSET, SUNIONSTORE 등은 오류가 납니다. 해시 태그로 같은 슬롯에 모으거나, 애플리케이션에서 개별 요청으로 처리해야 합니다.
데이터베이스 번호 제한: Cluster에서는 SELECT 명령으로 DB 번호를 바꿀 수 없습니다. 오직 DB 0만 사용 가능합니다.
🐍 Python으로 Cluster 연결
# pip install redis[hiredis] (redis-py에 Cluster 지원 내장)
from redis.cluster import RedisCluster
# Cluster 클라이언트 생성
rc = RedisCluster(
host="127.0.0.1",
port=7000,
decode_responses=True,
skip_full_coverage_check=True
)
# 일반 명령 (자동 리다이렉트)
rc.set("user:1", "alice")
print(rc.get("user:1")) # → "alice"
# 해시 태그로 MSET/MGET
rc.mset({
"order:{1000}:item": "coffee",
"order:{1000}:status": "pending",
"order:{1000}:qty": "2"
})
values = rc.mget("order:{1000}:item", "order:{1000}:status", "order:{1000}:qty")
print(values) # → ['coffee', 'pending', '2']
# 클러스터 정보
print(rc.cluster_info())
📌 11편 핵심 요약
- 16,384 해시 슬롯: 모든 키는 CRC16 % 16384 슬롯에 배정
- MOVED 리다이렉트: 엉뚱한 노드에 요청하면 올바른 노드로 안내 (
-c옵션으로 자동) - 해시 태그 {}: 관련 키를 같은 슬롯에 모아 멀티키 명령 가능
- 최소 6노드: 3 Primary + 3 Replica
- Sentinel vs Cluster: HA vs 수평 확장 — 목적에 따라 선택
✅ 11편 체크리스트
- 16,384 슬롯과 CRC16 해시를 이용한 키 배분 방식을 이해했다
- redis-cli -c로 클러스터에 접속하고 MOVED 리다이렉트를 확인했다
- 해시 태그 {} 없이 MGET이 실패하는 것과, 있으면 성공하는 것을 확인했다
- CLUSTER INFO, CLUSTER NODES로 클러스터 상태를 확인했다
- Sentinel과 Cluster의 선택 기준을 설명할 수 있다
- Cluster에서 SELECT 명령을 쓸 수 없다는 제약을 알고 있다
🧠 퀴즈 3문항
Q1. Redis Cluster에서 총 슬롯 수는 몇 개인가요?
Q2. 해시 태그 order:{1000}:item 에서 슬롯 계산에 사용되는 부분은?
slot = CRC16("1000") % 16384로 계산합니다. 이를 통해 order:{1000}:item, order:{1000}:status 등이 모두 같은 슬롯에 저장됩니다.Q3. 메모리 부족이 문제라면 Sentinel을 쓰나요, Cluster를 쓰나요?
📝 과제 3가지
- 슬롯 확인:
redis-cli -c -p 7000 CLUSTER KEYSLOT user:1000으로 특정 키의 슬롯 번호를 확인하고, 어떤 노드가 그 슬롯을 담당하는지 CLUSTER NODES와 비교하세요. - 노드 추가: 새 노드를 실행하고 CLUSTER MEET으로 클러스터에 합류시킨 후, CLUSTER RESHARD로 슬롯 일부를 이전해 보세요.
- 장애 시뮬레이션: Primary 노드 하나를 종료하고 Replica가 자동으로 승격되는지 CLUSTER NODES로 확인하세요.
'개발 > REDIS' 카테고리의 다른 글
| #12 🔐 보안·성능·관측: ACL·eviction·latency (0) | 2026.03.19 |
|---|---|
| #10 🔄 복제·고가용성: Replication·Sentinel (0) | 2026.03.19 |
| #9 💾 퍼시스턴스: RDB·AOF·복구 체크 (0) | 2026.03.19 |
| #8 ⚔️ 동시성 제어: 트랜잭션(MULTI/EXEC)·WATCH (0) | 2026.03.19 |
| #7 📡 Pub/Sub vs Streams: 실시간 메시징 (0) | 2026.03.19 |