Redis 핵심 정리 시리즈 7편. Sentinel·Cluster를 사옥 안전 감시단·여러 동 분산 비유로 풀어가며 — 마스터-레플리카 복제, 자동 페일오버, 16384개 해시 슬롯, 해시 태그({}), 클러스터 노드 추가/제거, 메모리 정책(LRU·LFU), TLS·ACL·SLOWLOG, 장애 복구 시나리오, Docker Compose 구성까지 처음 보는 사람도 따라올 수 있게 친절하게 풀어쓴 7편.
이 글은 Redis 핵심 정리 시리즈의 일곱 번째 편입니다. 1~6편이 단일 Redis 서버 안에서의 이야기였다면, 7편은 본격적으로 여러 서버를 묶어 운영하는 영역으로 넘어갑니다. 이 단계에 오면 두 가지 개념이 큰 산처럼 등장해요 — Sentinel(고가용성)과 Cluster(수평 확장).
이 7편에서는 두 개념을 사옥 비유로 풀어 갑니다. Sentinel은 사옥 안전 감시단, Cluster는 사옥을 여러 동으로 나눠 데이터를 분산하는 구조예요. 둘은 해결하려는 문제도 다르고 적합한 자리도 다릅니다. 이 차이를 머리에 박아 두는 게 7편의 핵심이에요.
왜 Cluster·Sentinel이 처음엔 어렵게 느껴질까요
이유는 네 가지예요.
첫째, Sentinel과 Cluster의 차이가 한 번에 안 잡힙니다. 둘 다 "여러 서버"라는 이미지가 있어 비슷해 보이는데, 해결하려는 문제가 다릅니다. Sentinel은 "마스터가 죽으면 자동으로 새 마스터를 뽑는다", Cluster는 "데이터를 여러 서버에 쪼개 분산한다" — 이 구분이 처음엔 흐릿해요.
둘째, 숫자가 갑자기 많이 등장합니다. 16384개 슬롯, 5초 타임아웃, 26379 Sentinel 포트, 6379 Redis 포트, 최소 3개 Sentinel, 최소 6개 Cluster 노드 — 한 번에 외울 수 없는 숫자가 쏟아져요.
셋째, 마스터·레플리카·노드·슬롯 용어가 머리를 꼬이게 합니다. 같은 마스터인데 Sentinel 맥락에서는 "감시 대상", Cluster 맥락에서는 "슬롯 담당자"로 의미가 살짝 다릅니다.
넷째, 장애 시나리오가 머리에 안 그려져요. "마스터가 죽으면 페일오버" 같은 한 줄로는 실제로 어떤 단계로 어떻게 흘러가는지 시뮬레이션이 안 돼서, 운영 자신감이 안 붙습니다.
해결법은 한 가지예요. 사옥 비유를 두 갈래로 박아 두는 겁니다. Sentinel은 사옥 한 동을 24시간 지키는 안전 감시단, Cluster는 사옥 자체를 여러 동으로 쪼갠 캠퍼스 구조로 잡으면 갑자기 명확해집니다. 이 글은 그 비유를 따라 처음부터 풀어 갑니다.
단일 Redis 서버의 한계 — 왜 묶어야 할까요
단일 Redis 서버는 단순하고 빠르지만 두 가지 근본 문제가 있어요.
첫째, 서버가 다운되면 Redis를 쓰는 모든 서비스가 멈춥니다(SPOF, Single Point of Failure). 회사 비유로 — 사옥 한 채에 모든 직원이 모여 있는데 그 사옥이 정전되면 회사 전체가 멈추는 셈이에요.
둘째, 단일 서버 메모리 크기를 초과하는 데이터를 저장할 수 없어요. 사옥 한 채의 사물함 용량에 한계가 있는데 사물함을 더 늘릴 수 없어 곤란한 상황이죠.
단일 서버 문제:
Redis 서버 다운 → 전체 서비스 중단 (SPOF)
메모리 초과 → 저장 불가
해결책:
복제(Replication): 고가용성 (HA, High Availability)
클러스터링: 수평 확장 (Horizontal Scaling)
이 두 문제를 푸는 두 가지 도구가 복제(Replication) 와 클러스터링(Clustering) 이에요. 차근차근 풀어 갑니다.
복제 — 마스터-레플리카 구조
Redis 복제(Replication) 는 하나의 마스터(Master)와 여러 레플리카(Replica)로 구성돼요. 마스터는 쓰기 작업을 처리하고, 레플리카는 마스터의 데이터를 실시간으로 복사합니다. 레플리카는 읽기 전용으로 사용해 읽기 부하를 분산할 수 있어요.
회사 비유로 — 본점이 있고 여러 분점이 있는 셈이에요. 본점(마스터) 에는 새 자료가 들어오면 등록하고, 분점(레플리카) 에는 본점에서 자료를 복사해 나눠 줍니다. 손님은 분점에서 자료를 조회만 할 수 있고(읽기 분산), 새 자료 등록은 항상 본점에 가서 해야 해요.
마스터 (M) ──→ 레플리카1 (R1) [읽기 전용]
──→ 레플리카2 (R2) [읽기 전용]
──→ 레플리카3 (R3) [읽기 전용]
쓰기 → 마스터만 처리
읽기 → 마스터 또는 레플리카 선택 가능
복제 설정은 두 가지 방식이 있어요.
# 방법 1: redis.conf에서 설정
# 레플리카 서버의 설정 파일
replicaof 192.168.1.100 6379 # 마스터의 IP:PORT
masterauth your_master_password # 마스터 인증 비밀번호
# 방법 2: redis-cli에서 런타임 설정
redis-cli -h replica-host REPLICAOF 192.168.1.100 6379
# 복제 상태 확인
redis-cli INFO replication
# role:master 또는 role:slave
# connected_slaves:2
# slave0:ip=192.168.1.101,port=6379,state=online
복제 동작 원리는 다음과 같아요.
초기 동기화:
레플리카 연결 → 마스터가 RDB 스냅샷 생성 → 레플리카에 전송
→ 레플리카가 스냅샷 적용 → 이후 변경사항 실시간 스트리밍
지속적 동기화:
마스터의 모든 쓰기 명령 → 레플리카에 비동기 전송
레플리카 동기화 지연: 보통 < 10ms
여기서 시험 함정이 하나 있어요. 복제는 비동기입니다. 마스터가 쓰기를 받자마자 응답하고, 그 후에 레플리카로 전파해요. 그래서 레플리카에 즉시 반영되지 않은 시점에 마스터가 죽으면 일부 쓰기가 사라질 수 있습니다. 일관성이 절대적인 자리에는 별도 보강이 필요해요.
Sentinel — 사옥 안전 감시단
복제만 해두면 마스터가 죽었을 때 수동으로 레플리카를 새 마스터로 승격해야 합니다. 이걸 자동화하는 게 Redis Sentinel이에요.
Sentinel은 마스터와 레플리카를 지속적으로 모니터링하다가 마스터 장애를 감지하면 자동으로 레플리카를 새 마스터로 승격시켜요(Automatic Failover). 클라이언트는 Sentinel에 질의해 현재 마스터 주소를 알 수 있습니다.
회사 비유로 — Sentinel은 사옥을 24시간 지키는 안전 감시단이에요. 본점에 불이 나거나 정전이 되면 감시단들이 회의를 열어 "본점이 다운됐다"는 합의를 보고, 분점 중 하나를 새 본점으로 승격시킵니다. 그리고 모든 직원에게 새 본점 주소를 자동으로 알려요.
Sentinel 구성 (최소 3개 권장):
Sentinel1 ─┐
Sentinel2 ─┼─ 감시 → Master(M)
Sentinel3 ─┘ ↓ 복제
Replica1(R1)
Replica2(R2)
마스터 장애 발생:
Sentinel들이 마스터 다운 감지 (과반수 투표)
→ 레플리카 중 하나를 새 마스터로 선출
→ 다른 레플리카들이 새 마스터를 따름
→ 클라이언트에게 새 마스터 주소 알림
여기서 정말 중요한 시험 함정 — Sentinel은 최소 3개가 권장됩니다. 왜냐하면 페일오버 결정은 과반수 투표로 이뤄지기 때문이에요. 2개만 있으면 한 쪽이 다운되면 과반수가 안 만들어지고, 1개는 자기 자신이 죽으면 끝이라 의미가 없어요. 3개부터 의미 있는 합의가 가능합니다.
Sentinel 설정
# sentinel.conf
port 26379
sentinel monitor mymaster 192.168.1.100 6379 2
# mymaster: 모니터링할 마스터 이름
# 2: 마스터 다운 판단에 필요한 Sentinel 수 (과반수)
sentinel auth-pass mymaster your_password
sentinel down-after-milliseconds mymaster 5000 # 5초 이상 응답 없으면 다운으로 판단
sentinel failover-timeout mymaster 60000 # 페일오버 타임아웃 60초
sentinel parallel-syncs mymaster 1 # 한 번에 동기화할 레플리카 수
# Sentinel 시작
redis-sentinel /path/to/sentinel.conf
# 또는
redis-server /path/to/sentinel.conf --sentinel
Sentinel은 포트 26379를 표준으로 써요. 일반 Redis가 6379이고 그 앞에 2를 붙인 형태인데, 이 숫자도 시험에 자주 나옵니다.
자세한 설정과 동작은 Redis 공식 Sentinel 문서에서 확인할 수 있어요.
TypeScript에서 Sentinel 사용
import { createClient } from 'redis';
// Sentinel을 통한 Redis 연결
const client = createClient({
sentinel: {
sentinels: [
{ host: '192.168.1.101', port: 26379 },
{ host: '192.168.1.102', port: 26379 },
{ host: '192.168.1.103', port: 26379 },
],
name: 'mymaster', // sentinel.conf의 모니터링 이름
},
password: 'your_password',
});
await client.connect();
// 이후 일반 Redis 명령어 사용과 동일
// 페일오버 발생 시 자동으로 새 마스터에 재연결
클라이언트는 Sentinel 목록만 알면 됩니다. 마스터가 누구인지, 페일오버 됐는지는 Sentinel이 알려 줘요. 페일오버가 일어나도 클라이언트는 자동으로 새 마스터에 재연결됩니다.
Redis Cluster — 사옥을 여러 동으로 분산
Sentinel은 고가용성을 해결하지만 데이터 크기 제한은 못 풀어 줘요. 단일 마스터 RAM이 곧 데이터 한계니까요. 이걸 푸는 게 Redis Cluster입니다.
Cluster는 데이터를 여러 노드에 자동 분산(샤딩)해요. 단일 서버 메모리 한계를 넘어 수평 확장이 가능하고, 일부 노드가 다운돼도 다른 노드는 계속 서비스합니다.
회사 비유로 — Cluster는 사옥을 여러 동(棟)으로 쪼갠 캠퍼스 구조예요. 1동, 2동, 3동에 사물함을 분산 배치하고, 자료마다 어느 동에 보관할지 미리 정해 둡니다. 한 동이 정전돼도 다른 동은 계속 일할 수 있어요.
Redis Cluster (6노드: 마스터 3 + 레플리카 3):
마스터1 (슬롯 0-5460) ──→ 레플리카1
마스터2 (슬롯 5461-10922) ──→ 레플리카2
마스터3 (슬롯 10923-16383)──→ 레플리카3
총 슬롯 수: 16384개
각 키는 해시 슬롯으로 매핑: slot = CRC16(key) % 16384
여기서 시험 함정이 하나 있어요. Cluster의 총 슬롯 수는 16384개입니다. 어떤 키든 CRC16(key) % 16384로 슬롯이 결정되고, 그 슬롯이 어느 마스터에 있는지에 따라 어느 노드에 저장될지 자동으로 결정돼요. 이 16384라는 숫자도 시험에 자주 나오는 단골입니다.
해시 슬롯과 키 분배
# 키의 해시 슬롯 계산
redis-cli CLUSTER KEYSLOT "user:1000"
# (integer) 7638 → 마스터2의 담당 슬롯
# 슬롯 분포 확인
redis-cli CLUSTER INFO
redis-cli CLUSTER NODES
redis-cli CLUSTER SLOTS
회사 비유로 — 자료 봉투에 이름을 적으면 그 이름의 해시값에 따라 자동으로 어느 동의 사물함에 갈지 결정되는 거예요. user:1000이라는 이름은 7638번 슬롯에 매핑되고, 그 슬롯을 담당하는 마스터로 자동 라우팅됩니다.
해시 태그 — 같은 동에 묶어 두기
여러 키를 같은 슬롯에 배치해야 하는 경우가 있어요. MULTI/EXEC 트랜잭션이나 MGET 같은 다중 키 명령어는 동일 슬롯의 키만 처리할 수 있기 때문이에요.
이 때 중괄호 {} 를 사용합니다. 중괄호 안의 내용으로만 슬롯을 계산하니, 같은 태그를 가진 키들은 모두 같은 슬롯으로 들어가요.
# 중괄호 안의 내용으로만 슬롯 계산
# user:1000:profile과 user:1000:settings를 같은 슬롯에 배치
CLUSTER KEYSLOT "{user:1000}.profile" # user:1000으로 슬롯 계산
CLUSTER KEYSLOT "{user:1000}.settings" # 동일한 슬롯
# 일반 키 vs 해시 태그 키
SET user:1000:profile "..." # 슬롯: CRC16("user:1000:profile") % 16384
SET {user:1000}.profile "..." # 슬롯: CRC16("user:1000") % 16384
회사 비유로 — {} 는 "이 자료들은 같은 동에 모아 두라"는 라벨이에요. 한 사용자에 묶이는 자료(프로필·설정·세션)는 모두 같은 동에 보관해 두면 트랜잭션이나 다중 키 조회가 가능해집니다.
Cluster 설정
# redis.conf 설정
port 7001
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000 # 노드 타임아웃 5초
appendonly yes # AOF 활성화 권장
# 6개 인스턴스 시작 (7001~7006)
redis-server redis-7001.conf
redis-server redis-7002.conf
redis-server redis-7003.conf
redis-server redis-7004.conf
redis-server redis-7005.conf
redis-server redis-7006.conf
# 클러스터 생성 (--cluster-replicas 1: 각 마스터에 레플리카 1개)
redis-cli --cluster create \
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 127.0.0.1:7006 \
--cluster-replicas 1
# 클러스터 상태 확인
redis-cli --cluster check 127.0.0.1:7001
redis-cli -c CLUSTER INFO # -c: 클러스터 모드 활성화
여기서 시험 함정이 하나 있어요. Cluster의 최소 노드 수는 6개입니다. 마스터 3개 + 각각의 레플리카 3개. 마스터가 3개 미만이면 페일오버 합의가 어려워지고, 레플리카가 없으면 마스터 다운 시 데이터를 잃어요.
자세한 클러스터 운영은 Redis 공식 scaling 문서에서 확인할 수 있어요.
TypeScript에서 Cluster 사용
import { createCluster } from 'redis';
const cluster = createCluster({
rootNodes: [
{ url: 'redis://127.0.0.1:7001' },
{ url: 'redis://127.0.0.1:7002' },
{ url: 'redis://127.0.0.1:7003' },
],
defaults: {
password: 'your_password',
},
});
await cluster.connect();
// 일반 명령어 사용 (자동으로 올바른 노드로 라우팅)
await cluster.set('user:1000', 'Alice'); // 자동으로 해당 슬롯의 마스터로 라우팅
const value = await cluster.get('user:1000');
// 해시 태그로 같은 노드에 배치
await cluster.set('{user:1000}.profile', profileData);
await cluster.set('{user:1000}.settings', settingsData);
// 이 두 키는 같은 노드에 저장됨 → MGET, 트랜잭션 가능
클러스터 운영 — 노드 추가/제거
운영 중에 데이터가 늘면 노드를 추가해 슬롯을 재분배해야 합니다.
# 새 마스터 노드 추가
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001
# 127.0.0.1:7007: 새 노드
# 127.0.0.1:7001: 기존 클러스터의 임의 노드
# 새 레플리카 노드 추가
redis-cli --cluster add-node --cluster-slave --cluster-master-id <master-id> \
127.0.0.1:7008 127.0.0.1:7001
# 슬롯 재분배 (새 마스터에 슬롯 이동)
redis-cli --cluster rebalance 127.0.0.1:7001
# 또는 직접 슬롯 이동
redis-cli --cluster reshard 127.0.0.1:7001
노드 제거 시에는 슬롯을 다른 노드로 먼저 옮겨야 합니다. 슬롯이 남아 있는 채로 노드를 빼면 그 슬롯의 데이터에 접근할 수 없어져요.
# 노드 제거 전 슬롯을 다른 노드로 이동
redis-cli --cluster reshard --cluster-from <node-id> --cluster-to <other-node-id> \
--cluster-slots <num-slots> 127.0.0.1:7001
# 슬롯이 없는 노드 제거
redis-cli --cluster del-node 127.0.0.1:7001 <node-id>
단일 / Sentinel / Cluster — 한눈에 비교
| 특성 | 단일 서버 | Sentinel | Cluster |
|---|---|---|---|
| 고가용성 | X | O | O |
| 자동 페일오버 | X | O | O |
| 수평 확장 | X | X (읽기만) | O |
| 최대 데이터 | RAM 크기 | 단일 마스터 RAM | 노드 수 × RAM |
| 다중 키 명령어 | O | O | 제한적 (해시 태그 필요) |
| 트랜잭션 | O | O | 제한적 (같은 슬롯만) |
| 설정 복잡도 | 낮음 | 중간 | 높음 |
| 최소 노드 수 | 1 | 3 (Sentinel) + 2 (마스터+레플리카) | 6 |
| 사용 사례 | 개발/테스트, 소규모 | 중소규모 HA | 대규모 확장 |
여기까지 따라오셨다면 한 가지 의문이 들 거예요. "그럼 어디까지 Sentinel로 가고, 어디부터 Cluster를 써야 하나?" — 정답은 데이터 크기가 가른다는 점입니다. 단일 서버 RAM(예: 64GB) 안에서 해결되면 Sentinel로 충분하고, 그걸 넘어가면 Cluster로 넘어가요.
메모리 관리 — maxmemory와 정책
운영 중인 Redis는 메모리 사용량을 항상 감시해야 합니다. 메모리가 가득 차면 어떻게 동작할지를 미리 정해 둬야 해요.
메모리 사용량 모니터링
# 전체 메모리 정보
redis-cli INFO memory
# 주요 지표:
# used_memory: 현재 사용 중인 메모리
# used_memory_rss: OS가 할당한 메모리 (단편화 포함)
# maxmemory: 설정된 최대 메모리
# mem_fragmentation_ratio: 메모리 단편화 비율 (1.5 이상이면 주의)
# 메모리 사용량이 많은 키 찾기
redis-cli --bigkeys
# 특정 키의 메모리 사용량
redis-cli MEMORY USAGE some-key
redis-cli MEMORY USAGE some-key SAMPLES 5
메모리 정책(Eviction Policy)
# redis.conf 또는 CONFIG SET
maxmemory 2gb
maxmemory-policy allkeys-lru
# 정책 종류:
# noeviction : 메모리 한계 시 에러 반환 (기본값)
# allkeys-lru : 모든 키 중 가장 오래 사용 안 한 키 삭제
# volatile-lru : TTL 있는 키 중 LRU 삭제
# allkeys-random : 모든 키 중 무작위 삭제
# volatile-random : TTL 있는 키 중 무작위 삭제
# volatile-ttl : TTL이 가장 짧은 키부터 삭제
# allkeys-lfu : 사용 빈도가 낮은 키 삭제 (Redis 4.0+)
# volatile-lfu : TTL 있는 키 중 사용 빈도가 낮은 키 삭제
여기서 시험 함정이 하나 있어요. 기본값은 noeviction 으로, 메모리가 가득 차면 쓰기에 에러를 반환합니다. 캐시 용도라면 거의 무조건 allkeys-lru 또는 allkeys-lfu 로 바꿔 두는 게 안전해요. LRU(가장 오래 안 쓴 것 먼저)와 LFU(가장 적게 쓴 것 먼저)는 자주 비교에 등장합니다.
메모리 최적화 기법
# Hash, List, Set의 인코딩 최적화
# 데이터가 작을 때 압축된 형식 사용 (ziplist/listpack)
hash-max-listpack-entries 128 # Hash를 ziplist로 저장하는 최대 필드 수
hash-max-listpack-value 64 # 최대 필드 값 크기 (bytes)
zset-max-listpack-entries 128
zset-max-listpack-value 64
list-max-listpack-size -2 # 최대 8kb의 ziplist
set-max-intset-entries 512 # 정수만 있는 Set의 intset 크기
보안 — TLS·ACL·방화벽
운영 환경의 Redis는 반드시 보안 설정을 거쳐야 합니다. Redis는 기본적으로 빠른 동작을 우선하기 때문에, 보안은 운영자가 직접 챙겨야 해요.
TLS/SSL 설정
# redis.conf TLS 설정
tls-port 6380
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-auth-clients yes # 클라이언트 인증서 요구
# TLS 연결
redis-cli -h localhost -p 6380 --tls \
--cert /etc/redis/tls/client.crt \
--key /etc/redis/tls/client.key \
--cacert /etc/redis/tls/ca.crt
ACL — 사용자별 세밀한 권한 관리
Redis 6.0부터는 ACL(Access Control List) 로 사용자별 권한을 관리할 수 있어요. 각 사용자에게 특정 명령어나 키 패턴 접근 권한을 따로 부여할 수 있습니다.
# ACL 사용자 생성
ACL SETUSER alice on >password123 ~users:* &* +get +set +del
# on: 활성화
# >password123: 비밀번호 설정
# ~users:*: users: 로 시작하는 키만 접근 허용
# &*: 모든 채널 구독/발행 허용
# +get +set +del: GET, SET, DEL 명령어 허용
# 읽기 전용 사용자
ACL SETUSER readonly on >readpass ~* +@read -@write
# ACL 목록 조회
ACL LIST
ACL WHOAMI # 현재 사용자 확인
ACL CAT # 명령어 카테고리 목록
# redis.conf에서 ACL 파일 지정
aclfile /etc/redis/users.acl
회사 비유로 — ACL은 출입증마다 어느 층, 어느 사물함, 어떤 작업이 가능한지 따로 부여하는 시스템이에요. 운영자는 어드민 권한, 모니터링 시스템은 읽기 전용, 배치 잡은 특정 키 패턴만 — 이렇게 분리할 수 있습니다.
방화벽 설정
# Redis는 기본적으로 모든 인터페이스에서 수신
# redis.conf에서 특정 인터페이스만 바인딩
bind 127.0.0.1 192.168.1.100 # 로컬 및 내부 IP만
# 보호 모드 활성화 (기본값)
protected-mode yes
# 비밀번호 설정
requirepass your_strong_password
모니터링 — INFO·SLOWLOG·CLIENT
운영 자신감은 모니터링에서 나와요. 자주 쓰는 명령어 4종을 정리합니다.
INFO 명령어
# 전체 정보
redis-cli INFO
# 섹션별 조회
redis-cli INFO server # 서버 정보
redis-cli INFO clients # 연결된 클라이언트
redis-cli INFO memory # 메모리 사용
redis-cli INFO stats # 통계 (히트율, 요청 수)
redis-cli INFO replication # 복제 상태
redis-cli INFO cpu # CPU 사용량
redis-cli INFO keyspace # DB별 키 정보
MONITOR — 실시간 명령어 추적
# 실시간 명령어 모니터링 (개발/디버깅 전용, 운영 환경 주의)
redis-cli MONITOR
# 모든 명령어가 실시간으로 출력됨
# 성능에 영향을 주므로 운영 환경에서는 짧게 사용
여기서 시험 함정이 하나 있어요. MONITOR는 운영 환경에서 오래 켜두면 안 됩니다. 모든 명령어를 실시간 출력하느라 성능이 크게 떨어져요. 디버깅 목적으로 짧게(수 초~수십 초) 켰다가 끄는 게 정답입니다.
SLOWLOG — 느린 쿼리 추적
# 느린 쿼리 로깅 설정
redis-cli CONFIG SET slowlog-log-slower-than 10000 # 10ms 이상인 명령어 기록
redis-cli CONFIG SET slowlog-max-len 128 # 최대 128개 기록
# 느린 쿼리 조회
redis-cli SLOWLOG GET 10 # 최근 10개
redis-cli SLOWLOG LEN # 총 레코드 수
redis-cli SLOWLOG RESET # 초기화
성능 문제 진단할 때 가장 먼저 보는 명령이에요. Redis는 단일 스레드라 한 명령이 오래 걸리면 그 동안 다른 명령이 대기합니다. SLOWLOG로 누가 시간을 잡아먹고 있는지를 빠르게 잡아낼 수 있어요.
CLIENT 명령어
# 연결된 클라이언트 목록
redis-cli CLIENT LIST
# 특정 클라이언트 이름 설정
redis-cli CLIENT SETNAME my-app-server
# 유휴 클라이언트 종료
redis-cli CLIENT KILL ID <client-id>
redis-cli CLIENT KILL ADDR 192.168.1.101:54321
# 클라이언트 수 제한
redis-cli CONFIG SET maxclients 10000
장애 복구 시나리오
마스터 장애 (Sentinel)
회사 비유로 — 본점이 정전됐을 때 안전 감시단들이 어떤 단계로 새 본점을 뽑는지 한 줄씩 따라가 보면 다음과 같아요.
시나리오: 마스터 서버 다운
1. Sentinel들이 마스터 ping 실패 감지
2. 5초 후 (down-after-milliseconds) "주관적 다운(SDOWN)" 판정
3. 과반수 Sentinel 동의 시 "객관적 다운(ODOWN)" 판정
4. 리더 Sentinel 선출 (Raft 알고리즘)
5. 가장 적합한 레플리카 선출 (복제 우선순위, 복제 오프셋 등 기준)
6. 선출된 레플리카를 새 마스터로 승격
7. 나머지 레플리카들이 새 마스터를 따르도록 재구성
8. 클라이언트에게 새 마스터 주소 알림 (+switch-master 이벤트)
용어가 두 단어 등장해요 — SDOWN(주관적 다운)은 한 Sentinel이 보기에 다운, ODOWN(객관적 다운)은 과반수 Sentinel이 동의한 다운입니다. SDOWN만으로는 페일오버가 일어나지 않아요. ODOWN까지 가야 새 마스터 선출이 시작됩니다.
클러스터 노드 장애
시나리오: 클러스터 마스터 노드 다운
1. 다른 노드들이 gossip 프로토콜로 장애 감지
2. cluster-node-timeout(기본 15초) 후 PFAIL(possible failure) 판정
3. 과반수 마스터 동의 시 FAIL 판정
4. 해당 마스터의 레플리카가 새 마스터로 선출
5. 슬롯 재매핑 완료
주의: 모든 슬롯이 서빙 가능한 상태여야 클러스터가 정상 동작
레플리카 없는 마스터 장애 시 클러스터 전체 서비스 중단
여기서 정말 중요한 시험 함정 — 레플리카 없는 마스터가 다운되면 클러스터 전체가 중단됩니다. 그 마스터가 담당하던 슬롯에 데이터가 사라져 버리기 때문이에요. 그래서 운영에서는 모든 마스터에 레플리카를 최소 1개씩 두는 게 표준입니다.
데이터 복구
# RDB 파일에서 복구
# dump.rdb를 Redis 데이터 디렉토리에 복사 후 재시작
cp /backup/dump-20231101.rdb /var/lib/redis/dump.rdb
redis-server redis.conf
# AOF 파일 복구
redis-check-aof --fix appendonly.aof # 손상된 AOF 파일 복구
redis-server --appendonly yes # AOF 복구 모드로 시작
영속성 전략(RDB·AOF)는 4편에서 자세히 다뤘어요. 운영 환경에서는 두 가지를 함께 쓰는 하이브리드가 표준입니다.
Docker Compose로 복제 환경 구성
로컬에서 마스터-레플리카-Sentinel 환경을 띄워 실험하고 싶다면 Docker Compose로 1분 만에 가능해요.
# docker-compose.yml
version: '3.8'
services:
redis-master:
image: redis:7
ports:
- "6379:6379"
command: redis-server --requirepass password123
redis-replica1:
image: redis:7
ports:
- "6380:6379"
command: redis-server --replicaof redis-master 6379 --masterauth password123 --requirepass password123
depends_on:
- redis-master
redis-replica2:
image: redis:7
ports:
- "6381:6379"
command: redis-server --replicaof redis-master 6379 --masterauth password123 --requirepass password123
depends_on:
- redis-master
redis-sentinel:
image: redis:7
ports:
- "26379:26379"
command: >
redis-sentinel /sentinel.conf
volumes:
- ./sentinel.conf:/sentinel.conf
depends_on:
- redis-master
- redis-replica1
- redis-replica2
운영에서 자주 보는 함정 5가지
1. 단일 슬롯 제약 위반 — 다중 키 명령어
# 잘못된 방법: 클러스터에서 다중 키 명령어 (다른 슬롯)
MSET user:1 "Alice" user:2 "Bob"
# CROSSSLOT Keys in request don't hash to the same slot 에러!
# 올바른 방법 1: 해시 태그 사용
MSET {user}:1 "Alice" {user}:2 "Bob" # {user}로 슬롯 통일
# 올바른 방법 2: 각각 개별 명령어로
SET user:1 "Alice"
SET user:2 "Bob"
2. Sentinel vs Cluster 혼동
Sentinel: 고가용성 전용 (자동 페일오버)
→ 단일 마스터의 데이터 크기 제한은 해결 안 됨
→ 읽기 분산만 가능
Cluster: 수평 확장 (샤딩) + 고가용성
→ 데이터를 여러 노드에 분산
→ 다중 키 명령어 제한 있음
3. Cluster에서 Lua 스크립트 주의
-- 클러스터에서는 Lua 스크립트의 모든 키가 같은 슬롯에 있어야 함
-- 잘못된 방법: 다른 슬롯의 키 접근
redis.call('GET', KEYS[1]) -- user:1 → 슬롯 1000
redis.call('GET', KEYS[2]) -- item:1 → 슬롯 2000 (에러!)
-- 올바른 방법: 해시 태그로 같은 슬롯 보장
-- {tag}:user:1 과 {tag}:item:1 모두 "tag"의 슬롯으로 계산
4. 메모리 단편화 문제
# mem_fragmentation_ratio 확인
redis-cli INFO memory | grep mem_fragmentation_ratio
# 1.0: 정상
# 1.5 이상: 단편화 심각
# 1.0 미만: 스왑 사용 중 (매우 나쁨)
# 단편화 해소 (Redis 4.0+)
redis-cli MEMORY PURGE
# 또는 재시작을 통한 메모리 정리
# 이 경우 RDB/AOF 설정 확인 필요
여기서 시험 함정이 하나 있어요. mem_fragmentation_ratio가 1.0 미만이면 스왑 사용 중이라는 신호로, 매우 나쁜 상황입니다. RAM이 모자라 OS가 디스크 스왑을 쓰고 있다는 뜻이에요. Redis 성능 폭락의 주범입니다.
5. 네트워크 지연으로 인한 잘못된 페일오버
# Sentinel down-after-milliseconds를 너무 짧게 설정하면
# 일시적 네트워크 지연을 장애로 오판하여 불필요한 페일오버 발생
# 권장: 5000ms 이상 (5초)
sentinel down-after-milliseconds mymaster 5000
# 운영 환경에서는 15000~30000ms를 권장하는 경우도 있음
회사 비유로 — 안전 감시단이 너무 예민하면 본점에서 잠깐 무전이 끊겼을 뿐인데 "본점 다운"으로 판정하고 새 본점을 뽑아 버려요. 그러면 진짜 본점은 멀쩡한데 분점이 새 본점이 되는 헷갈리는 상황이 생깁니다. 타임아웃은 너무 짧지도 너무 길지도 않게 잡는 게 핵심이에요.
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 Redis 7편(Cluster·고가용성)의 핵심입니다. 시험 직전·실무 실수 방지를 위한 압축 노트로 마무리할게요.
- 단일 서버 한계 두 가지 — SPOF(단일 장애점) + 메모리 크기 제한
- 해결 두 갈래 — 복제(Replication) = HA, 클러스터(Clustering) = 수평 확장
- 마스터-레플리카 — 마스터만 쓰기, 레플리카는 읽기 전용 (읽기 분산)
- 복제는 비동기 — 마스터 다운 시 일부 쓰기 손실 가능
- Sentinel = 사옥 안전 감시단 — 마스터 다운 자동 감지·페일오버
- Sentinel 최소 3개, 페일오버는 과반수 투표
- Sentinel 포트 = 26379 (Redis는 6379)
- SDOWN(주관적 다운, 한 Sentinel만) → ODOWN(객관적 다운, 과반수 동의)
- 페일오버 단계 — Ping 실패 → SDOWN → ODOWN → 리더 Sentinel 선출 → 새 마스터 선출 → 재구성
- Cluster = 사옥 여러 동으로 분산 — 수평 확장 + HA
- 총 슬롯 수 = 16384개, 슬롯 =
CRC16(key) % 16384 - Cluster 최소 6노드 (마스터 3 + 레플리카 3)
- 다중 키 명령어 (
MGET·MSET·트랜잭션) — 같은 슬롯에서만 가능 - 해시 태그
{}— 중괄호 안 내용으로만 슬롯 계산, 같은 슬롯에 묶을 때 - 단일 vs Sentinel vs Cluster — 데이터 크기·HA 요구·복잡도가 결정
- maxmemory-policy — 캐시 용도라면
allkeys-lru또는allkeys-lfu - 기본값
noeviction— 캐시 운영에는 위험 (메모리 가득 차면 쓰기 에러) - LRU vs LFU — 가장 오래 안 쓴 것 vs 가장 적게 쓴 것
- TLS·ACL·
bind·requirepass— 운영 보안 4종 세트 - ACL — Redis 6.0+, 사용자별 키 패턴·명령어 권한 따로
MONITOR운영에서 길게 켜면 성능 폭락 — 디버깅 짧게만SLOWLOG— 느린 쿼리 진단 1순위 도구mem_fragmentation_ratio1.0 미만 = 스왑 사용 중 (매우 나쁨)- 레플리카 없는 마스터 다운 = 클러스터 전체 중단 — 모든 마스터에 레플리카 1개+
- Sentinel
down-after-milliseconds너무 짧으면 불필요한 페일오버 발생 (5초+ 권장) - 자주 헷갈리는 비교 — Sentinel vs Cluster = HA 전용 vs HA + 수평 확장
- 자주 헷갈리는 비교 — 노드 추가 vs 슬롯 재분배 = 추가만으로는 부족, reshard 필요
시리즈 다른 편
같은 시리즈의 다른 글들도 같은 친절 톤으로 묶어 정리되어 있어요.