k8s_redis_scaleout
쿠버네티스(Kubernetes) 환경에서 Redis Scale-Out (확장)
쿠버네티스 환경에서 레디스 확장
1. Redis-Cluster 확장 조언
쿠버네티스의 kubectl scale --replicas 명령으로 파드 수만 늘린다고 해서 Redis-Cluster가 실질적으로 확장되지 않습니다.
아래에서 Redis-Cluster를 실제 확장하는 표준 절차를 간단히 살펴보겠습니다.
- ① 쿠버네티스 명령으로 레디스 파드를 증설 (예: 6개 ➔ 10개 파드로 확장)
- ② 레디스
redis-cli --cluster add-node명령으로 증설된 노드들을 기존 Cluster에 참여시킴 - ③ 레디스
cluster rebalance명령으로 슬롯과 데이터(키)를 새로 추가된 레디스 노드들로 이동시킴 - 여기까지 완료되어야 비로소 Redis-Cluster의 확장이 완료된 것입니다.
💻 부하가 심한 상태(CPU 100%)에서 실시간 확장이 어려운 이유
- ③번 레디스 'cluster rebalance' 진행 시 슬롯과 데이터를 이동하는 과정에서 상당한 부하가 발생합니다. 기존 Redis-0, 1, 2에서 대용량 데이터를 신규 노드로 이동시켜야 하므로 네트워크 및 CPU 소모가 당연히 발생합니다. 이미 CPU 사용량이 100%인 상태에서 데이터 재배치(Rebalance) 작업까지 추가되면 기존 레디스의 응답시간(Latency)이 급격히 늘어나 서비스 장애로 이어질 수 있습니다.
- Rebalance 작업 중 성능 저하:
데이터 이동 중에는 애플리케이션의 키 읽기/쓰기 요청 시 기존 노드와 신규 노드 간에
ASK / MOVED Redirection(기존 레디스에 해당 키가 있는지 묻고, 없으면 새 레디스에 해당 키가 도착했는지 묻는) 과정이 빈번하게 발생하여 응답시간이 떨어지고 CPU 사용률이 더욱 상승합니다. - 클러스터 구조적 복잡성: 실제 확장은 마스터 노드의 홀수 개 유지 규칙(3개 ➔ 5개 등)과 1:1 복제(Replica) 구성을 함께 고려해야 하므로, 기존 6개 파드에서 10개 파드로 늘리는 등 다수의 노드를 한 번에 구성해야 하여 Rebalance 과정이 매우 복잡해집니다.
- nodes.conf 상태 불일치 및 장애 위험:
Rebalance 진행 도중 어떤 이유로든 파드 1~2개가 다운된다면 Redis-Cluster 전체 마비로 번질 수 있습니다.
특히 슬롯 이동 중에 노드가 다운되면 각 파드에 저장된
nodes.conf파일의 슬롯 소유권 상태 정보가 서로 일치하지 않아 자동 복구가 불가능해질 위험이 높습니다. - [운영 가이드] 따라서 레디스의 부하 증가가 예상된다면, 미리 안정적인 시점(CPU 사용량 60% 이하)에 선제적으로 확장하시거나, 갑작스러운 부하 발생 시에는 부하가 가라앉은 안정된 시점을 기다렸다가 확장을 진행하시기 바랍니다.
🧑💻 Redis-Operator를 이용한 자동 확장
- Redis-Cluster 자동 확장을 하려면 'Redis-Operator'(별도 제품)를 이용해서 구축 가능합니다.
- Redis-Operator가 위에 설명한 'cluster add-node, rebalance' 같은 명령을 실행해 줍니다.
- 이 경우에도 확장 시점을 정하는 hpa.yaml 파일에 cpu: averageUtilization 값을 높게 설정하는 것은 권장되지 않습니다.
🌐 Redis-Operator 공급(URL)
- Redis-Operator (OT-CONTAINER-KIT)
설명: 오픈소스 커뮤니티에서 가장 활발히 사용되는 Redis Operator 중 하나입니다. `RedisCluster` Custom Resource(CRD)를 정의하면 노드 추가, 제거, Failover, Auto-scaling을 알아서 안전하게 처리해 줍니다.
관련 문서/Github: 🔗 redis-operator 🔗 getting-started
- Spotahome Redis Operator
설명: Redis-Sentinel 및 Redis-Cluster 아키텍처를 쿠버네티스 컨트롤러 형태로 안전하게 관리할 수 있도록 스페인 테크 기업 Spotahome에서 개발하여 공개한 오퍼레이터입니다.
관련 문서/Github: 🔗 Spotahome Redis Operator - Redis Enterprise K8s Operator (공식 레디스)
설명: Redis.io (Redis Ltd.) 공식 제공 오퍼레이터입니다. K8s HPA 및 Custom Metrics와 연동되어 노드 증설부터 Shard Rebalancing까지의 전 과정을 자동화합니다.
공식 가이드: 🔗 Redis Enterprise K8s Operator
2. Redis-Sentinel 확장 조언
Redis-Sentinel 환경에서 CPU 사용률이 100%에 도달하는 병목 현상은 거의 대부분 Master 노드에서 발생합니다. 단일 Master 구조 특성상 모든 데이터 변경(입력/수정/삭제) 요청 처리가 Master 1곳에 집중되기 때문입니다.
- 복제 노드(Replica) 증설의 한계: 이미 2개의 복제 노드가 읽기(Read) 트래픽을 분산 처리하고 있으므로, 복제 노드에 CPU 병목이 발생하는 경우는 극히 드뭅니다. 따라서 파드를 추가 증설하는 것은 단지 복제 노드를 1개 더 늘리는 것에 불과하며, Master에 집중된 쓰기(Write) 부하와 CPU 성능 병목을 전혀 해결할 수 없습니다.
- 읽기(Read) 분산의 한계점: 새로운 복제 노드가 추가되면 Master로부터 전체 데이터를 동기화(Full Resync)받는 과정이 발생합니다. 이 동기화 과정에서 Master 노드에 RDB 생성 및 네트워크 I/O 부하가 추가되어 오히려 Master의 CPU 상태가 악화될 수 있습니다.
💡 결론 및 최적의 대안
Master 부하로 인한 Sentinel 환경의 성능 한계에 직면했을 때, 파드(복제 노드) 증설은 올바른 해결책이 아닙니다. 근본적 해결책(Scale-Out / 아키텍처 전환)은 지속적인 쓰기 트래픽 증가가 예상된다면, 단일 Master 구조인 Sentinel을 벗어나 다중 Master로 쓰기 트래픽을 분산할 수 있는 Redis-Cluster 구조로 아키텍처를 전환해야 합니다.
Redis-Cluster 확장 방법
1. 파드 추가
1) 기존 상태 조회 🧮
redis-cluster-0~5: 6개 파드가 있다.
2) 파드 추가: 6개 -> 10개 ⚡
3) 파드 추가 후 확인 🧮
redis-cluster-6~9: 4개 파드 추가 생성 완료
2. Redis-Cluster 노드 추가
마스터로 추가되지만 슬롯이 할당되지 않았으므로 아직 데이터가 들어오지는 않는다.
1) redis-cluster-6 노드 추가: add-node
kubectl exec -it redis-cluster-0 -- redis-cli -a redisgate --cluster add-node
redis-cluster-6.redis-cluster-service.default.svc.cluster.local:18504
redis-cluster-0.redis-cluster-service.default.svc.cluster.local:18504
0번 레디스에 접속해서 6번 레디스를 클러스터에 추가한다.
출력 내용
2) redis-cluster-7 노드 추가: add-node
kubectl exec -it redis-cluster-0 -- redis-cli -a redisgate --cluster add-node
redis-cluster-7.redis-cluster-service.default.svc.cluster.local:18504
redis-cluster-0.redis-cluster-service.default.svc.cluster.local:18504
0번 레디스에 접속해서 7번 레디스를 클러스터에 추가한다. ⇒ '출력 내용' 생략
3. 슬롯 할당: rebalance
1) 'rebalance' 명령 실행 ⚡
추가된 노드에 슬롯을 할당: 'rebalance' 명령 실행
kubectl exec -it redis-cluster-0 -- redis-cli -a redisgate
--cluster rebalance redis-cluster-0.redis-cluster-service.default.svc.cluster.local:18504
--cluster-use-empty-masters
* 옮기는(Moving) 슬롯 개수만큼 '#'이 표시된다. 생략하지 않고 다 표시했습니다.
* 이동하는 키 개수만큼 시간이 걸린다.
2) 슬롯 할당 확인
3) Redis-Cluster 상태 확인: cluster info
4) Redis-Cluster 상태 확인: cluster nodes
4. 8, 9번 노드 추가
8, 9번 노드를 복제(Replica)로 추가한다.
1) 8번 노드 추가: add-node --cluster-slave
kubectl exec -it redis-cluster-0 -- redis-cli -a redisgate --cluster add-node
redis-cluster-8.redis-cluster-service.default.svc.cluster.local:18504
redis-cluster-6.redis-cluster-service.default.svc.cluster.local:18504 --cluster-slave
8번 노드를 6번 노드의 복제(Salve)로 추가한다.
옵션 '--cluster-slave' 사용: 🚨 '--cluster-replica' 옵션은 사용불가
(Redis-8.8.2 redis-cli.c 소스 확인)
출력 내용
2) 9번 노드 추가: add-node --cluster-slave
kubectl exec -it redis-cluster-0 -- redis-cli -a redisgate --cluster add-node
redis-cluster-9.redis-cluster-service.default.svc.cluster.local:18504
redis-cluster-7.redis-cluster-service.default.svc.cluster.local:18504 --cluster-slave
9번 노드를 7번 노드의 복제(Salve)로 추가한다. ⇒ '출력 내용' 생략
3) 추가된 복제 노드 확인
8, 9번이 복제(slave)로 추가 되었는지 확인: IP 199, 201 노드의 slaves가 '0'에서 '1'로 변경됨.
4) 추가된 복제 노드 확인
출력 결과를 보기 쉽게 정리했다.
5) 최종 결과 파드 확인 🧮
6) 메모리 확인 🧮
7) 🖧 Redis-Cluster 최종 파드 다이어그램
┌────────────────┐ ┌────────────────┐ ┌───────────────┐ ┌────────────────┐ ┌────────────────┐
│ Redis-0(174) │ │ Redis-1(165) │ │ Redis-2(167) │ │ Redis-6(199) │ │ Redis-7(201) │
│ 🟢Master-1 │ │ 🟢Master-2 │ │ 🟢Master-3 │ │ 🟢Master-4 │ │ 🟢Master-5 │
└──────┬─────────┘ └──────┬─────────┘ └──────┬────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │ │ │
│ ┌──────────────────│────────────────────┘ │ │
│ │ └────────────────────┐ │ │
└──────────────────┐ │ │ │
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌───────────────┐ ┌────────────────┐ ┌────────────────┐
│ Redis-3(169) │ │ Redis-4(175) │ │ Redis-5(173) │ │ Redis-8(203) │ │ Redis-9(205) │
│ 🟡Replica-1 │ │ 🟡Replica-2 │ │ 🟡Replica-3 │ │ 🟡Replica-4 │ │ 🟡Replica-5 │
└────────────────┘ └────────────────┘ └───────────────┘ └────────────────┘ └────────────────┘
🧑💻 정리
쿠버네티스 환경에서 Redis-Cluster 파드 확장을 완료하였습니다.
| << K8s Standalone ③ | K8s Redis Summary >> |
|---|
