들어가며
단일 Redis 인스턴스는 메모리와 처리량에 한계가 있습니다. **Redis Cluster**는 데이터를 여러 노드에 자동으로 분산(샤딩)하고, 노드 장애 시 자동 페일오버를 제공하는 네이티브 클러스터링 솔루션입니다.
이 글에서는 Redis Cluster의 아키텍처를 이해하고, 실제 구축부터 운영까지 단계별로 살펴봅니다.
Redis Cluster 아키텍처
해시 슬롯 (Hash Slots)
Redis Cluster는 **16,384개의 해시 슬롯**을 사용하여 데이터를 분산합니다:
키의 해시 슬롯 계산
HASH_SLOT = CRC16(key) % 16384
예시: 3개 마스터 노드
Node A: 슬롯 0 ~ 5460
Node B: 슬롯 5461 ~ 10922
Node C: 슬롯 10923 ~ 16383
클러스터 토폴로지
최소 권장 구성: 3 Master + 3 Replica = 6 노드
#
Master A (슬롯 0-5460) ←→ Replica A'
Master B (슬롯 5461-10922) ←→ Replica B'
Master C (슬롯 10923-16383) ←→ Replica C'
#
각 Master가 다운되면 해당 Replica가 자동 승격
6노드 Redis Cluster 구축
Docker Compose로 구축
docker-compose.yml
version: '3.8'
services:
redis-node-1:
image: redis:7.4
container_name: redis-node-1
ports:
- '7001:7001'
- '17001:17001'
volumes:
- ./redis-node-1:/data
command: >
redis-server
--port 7001
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.11
redis-node-2:
image: redis:7.4
container_name: redis-node-2
ports:
- '7002:7002'
- '17002:17002'
volumes:
- ./redis-node-2:/data
command: >
redis-server
--port 7002
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.12
redis-node-3:
image: redis:7.4
container_name: redis-node-3
ports:
- '7003:7003'
- '17003:17003'
volumes:
- ./redis-node-3:/data
command: >
redis-server
--port 7003
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.13
redis-node-4:
image: redis:7.4
container_name: redis-node-4
ports:
- '7004:7004'
- '17004:17004'
volumes:
- ./redis-node-4:/data
command: >
redis-server
--port 7004
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.14
redis-node-5:
image: redis:7.4
container_name: redis-node-5
ports:
- '7005:7005'
- '17005:17005'
volumes:
- ./redis-node-5:/data
command: >
redis-server
--port 7005
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.15
redis-node-6:
image: redis:7.4
container_name: redis-node-6
ports:
- '7006:7006'
- '17006:17006'
volumes:
- ./redis-node-6:/data
command: >
redis-server
--port 7006
--cluster-enabled yes
--cluster-config-file nodes.conf
--cluster-node-timeout 5000
--appendonly yes
--protected-mode no
--bind 0.0.0.0
networks:
redis-cluster:
ipv4_address: 172.20.0.16
networks:
redis-cluster:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/24
컨테이너 시작
docker compose up -d
클러스터 생성 (3 master + 3 replica)
docker exec -it redis-node-1 redis-cli --cluster create \
172.20.0.11:7001 172.20.0.12:7002 172.20.0.13:7003 \
172.20.0.14:7004 172.20.0.15:7005 172.20.0.16:7006 \
--cluster-replicas 1 --cluster-yes
클러스터 상태 확인
docker exec -it redis-node-1 redis-cli -p 7001 cluster info
docker exec -it redis-node-1 redis-cli -p 7001 cluster nodes
베어메탈/VM에서 구축
Redis 설치 (Ubuntu)
sudo apt update && sudo apt install -y redis-server
노드별 설정 파일 생성
cat > /etc/redis/redis-7001.conf << 'EOF'
port 7001
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 5000
appendonly yes
appendfilename "appendonly-7001.aof"
dbfilename dump-7001.rdb
dir /var/lib/redis/7001
logfile /var/log/redis/redis-7001.log
pidfile /var/run/redis/redis-7001.pid
protected-mode no
bind 0.0.0.0
메모리 설정
maxmemory 4gb
maxmemory-policy allkeys-lru
성능 튜닝
tcp-backlog 511
timeout 0
tcp-keepalive 300
EOF
디렉토리 생성
sudo mkdir -p /var/lib/redis/7001
sudo chown redis:redis /var/lib/redis/7001
서비스 시작
sudo redis-server /etc/redis/redis-7001.conf --daemonize yes
6개 노드 모두 시작 후 클러스터 생성
redis-cli --cluster create \
192.168.1.1:7001 192.168.1.2:7002 192.168.1.3:7003 \
192.168.1.4:7004 192.168.1.5:7005 192.168.1.6:7006 \
--cluster-replicas 1
클러스터 운영
데이터 읽기/쓰기
클러스터 모드로 접속 (-c 플래그)
redis-cli -c -h 172.20.0.11 -p 7001
MOVED 리다이렉션 자동 처리
172.20.0.11:7001> SET user:1000 "Kim Youngju"
-> Redirected to slot [3817] located at 172.20.0.11:7001
OK
172.20.0.11:7001> SET user:2000 "Park Minho"
-> Redirected to slot [8234] located at 172.20.0.12:7002
OK
Hash Tag로 같은 슬롯에 저장
{user:1000} 부분만 해시 계산에 사용됨
SET {user:1000}.profile "Kim Youngju"
SET {user:1000}.email "youngju@example.com"
SET {user:1000}.settings "{\"theme\":\"dark\"}"
같은 슬롯에 저장되므로 MGET 가능
MGET {user:1000}.profile {user:1000}.email
Python 클라이언트
from redis.cluster import RedisCluster
클러스터 연결
rc = RedisCluster(
startup_nodes=[
{"host": "172.20.0.11", "port": 7001},
{"host": "172.20.0.12", "port": 7002},
{"host": "172.20.0.13", "port": 7003},
],
decode_responses=True,
skip_full_coverage_check=True
)
기본 작업
rc.set("user:1000", "Kim Youngju")
print(rc.get("user:1000"))
파이프라인 (같은 슬롯의 키만)
pipe = rc.pipeline()
pipe.set("{user:1000}.name", "Kim Youngju")
pipe.set("{user:1000}.age", "30")
pipe.get("{user:1000}.name")
results = pipe.execute()
print(results)
클러스터 정보
print(rc.cluster_info())
노드 추가/제거
새 마스터 노드 추가
redis-cli --cluster add-node 172.20.0.17:7007 172.20.0.11:7001
슬롯 리밸런싱
redis-cli --cluster rebalance 172.20.0.11:7001
새 노드에 레플리카 추가
redis-cli --cluster add-node 172.20.0.18:7008 172.20.0.11:7001 \
--cluster-slave --cluster-master-id <master-node-id>
노드 제거 (먼저 슬롯을 다른 노드로 이동)
redis-cli --cluster reshard 172.20.0.11:7001 \
--cluster-from <removing-node-id> \
--cluster-to <target-node-id> \
--cluster-slots 5461 \
--cluster-yes
redis-cli --cluster del-node 172.20.0.11:7001 <removing-node-id>
자동 페일오버
페일오버 동작 과정
1. Master A 다운 감지 (cluster-node-timeout 초 후)
2. Replica A'가 다른 Master들에게 투표 요청
3. 과반수 Master가 승인하면 Replica A'가 Master로 승격
4. 새 Master A'가 기존 슬롯 담당
페일오버 테스트
docker stop redis-node-1
상태 확인 (Replica가 Master로 승격됨)
docker exec -it redis-node-2 redis-cli -p 7002 cluster nodes
수동 페일오버
Replica에서 실행 (graceful failover)
redis-cli -h 172.20.0.14 -p 7004 CLUSTER FAILOVER
강제 페일오버 (Master가 다운된 경우)
redis-cli -h 172.20.0.14 -p 7004 CLUSTER FAILOVER FORCE
모니터링
핵심 메트릭
클러스터 상태 확인
redis-cli -p 7001 cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_known_nodes:6
노드별 메모리 사용량
redis-cli -p 7001 info memory
used_memory_human:1.5G
maxmemory_human:4.0G
슬롯 분배 확인
redis-cli --cluster check 172.20.0.11:7001
Prometheus + Grafana 모니터링
docker-compose.monitoring.yml
services:
redis-exporter:
image: oliver006/redis_exporter:latest
environment:
- REDIS_ADDR=redis://172.20.0.11:7001
- REDIS_CLUSTER=true
ports:
- '9121:9121'
prometheus.yml
scrape_configs:
- job_name: 'redis-cluster'
static_configs:
- targets: ['redis-exporter:9121']
주요 Grafana 대시보드 쿼리
초당 명령 수
rate(redis_commands_processed_total[5m])
메모리 사용률
redis_memory_used_bytes / redis_memory_max_bytes * 100
키 수
redis_db_keys
연결된 클라이언트 수
redis_connected_clients
복제 지연
redis_replication_offset
트러블슈팅
CROSSSLOT 에러
에러: CROSSSLOT Keys in request don't hash to the same slot
원인: MGET, MSET 등에서 다른 슬롯의 키를 사용
해결: Hash Tag 사용
MGET {order:1}.items {order:1}.total # OK (같은 슬롯)
MGET order:1 order:2 # ERROR (다른 슬롯 가능)
클러스터 상태 복구
클러스터 상태가 fail인 경우
redis-cli --cluster fix 172.20.0.11:7001
슬롯이 누락된 경우
redis-cli --cluster fix 172.20.0.11:7001 --cluster-fix-with-unreachable-masters
마무리
Redis Cluster 운영의 핵심:
1. **최소 6노드**: 3 Master + 3 Replica로 고가용성 확보
2. **Hash Tag 활용**: 관련 키를 같은 슬롯에 배치
3. **자동 페일오버**: cluster-node-timeout 설정에 따라 자동 복구
4. **리샤딩**: 노드 추가/제거 시 슬롯 재분배
5. **모니터링**: Prometheus + redis_exporter로 상시 감시
**Q1. Redis Cluster의 해시 슬롯 개수는?**
16,384개
**Q2. 키의 해시 슬롯을 계산하는 공식은?**
CRC16(key) % 16384
**Q3. Hash Tag의 역할은?**
중괄호 안의 문자열만 해시 계산에 사용하여 관련 키를 같은 슬롯에 배치
**Q4. 자동 페일오버 시 Replica가 Master로 승격되려면?**
과반수 Master의 투표(승인)가 필요
**Q5. CROSSSLOT 에러의 원인과 해결법은?**
다른 슬롯의 키를 한 명령에서 사용할 때 발생. Hash Tag로 같은 슬롯에 배치하여 해결
**Q6. cluster-node-timeout의 역할은?**
노드 장애를 감지하는 시간. 이 시간 동안 응답이 없으면 장애로 판단
**Q7. 노드 제거 시 먼저 해야 하는 작업은?**
해당 노드의 슬롯을 다른 노드로 리샤딩(reshard)
현재 단락 (1/253)
단일 Redis 인스턴스는 메모리와 처리량에 한계가 있습니다. **Redis Cluster**는 데이터를 여러 노드에 자동으로 분산(샤딩)하고, 노드 장애 시 자동 페일오버를 제공...