레이블이 redis-cli인 게시물을 표시합니다. 모든 게시물 표시
레이블이 redis-cli인 게시물을 표시합니다. 모든 게시물 표시

redis 특정 슬롯에 저장하기

# CROSSSLOT Keys in request don't hash to the same slot
# mset, mget 의 키들은 하나의 슬롯(노드)에 있어야 한다.
# 키이름에 {xxx}: 같은 prefix 를 붙이면 xxx 로만 해싱해 슬롯을 지정한다.

# scan 0 으로 전체 조회는 현재 슬롯에서만 가능하기 때문에
# 키에 {xxx} hashing prefix 가 있으면
# 다음과 같이 특정 슬롯으로 이동 후 scan 0 으로 조회해야 한다.

redis-cli -h 10.10.10.101 -p 6379 -c -a "password123"
10.10.10.101:6379> get "{123}"
-> Redirected to slot [5555] located at 10.10.10.102:6379
(nil)
10.10.10.102:6379> scan 0
1) "0"
2) 1) "{123}:ysoftman-test-key1"
10.10.10.102:6379>

로컬에서 k8s redis cluster 접속

# k8s 에 redis cluster 를 구성하였다.
# redis 노드1개는 1개의 pod 로 구성되고, 이 pod 를 서비스로 묶었다.

# 다음과 클라이언트가 k8s 안의 pod(redis-cluster-0) 라면 접속이 잘된다.
kubectl --namespace redis exec -it redis-cluster-0 -- redis-cli -h {레디스 노드 중 하나} -p 6379 -c

# 실제 서비스 서버도 k8s 배포되어 운영시는 문제가 없지만
# 개발시에는 로컬에서 k8s redis 에 접근이 필요하다.
# 그래서 redis 의 k8s service 에 nodeport (32000) 설정하고 
# k8s nodeIP:nodeport 로 접속을 시도 하였다.
redis-cli -h {k8s 노드 중 하나} -p 32000 -c
# 접속은 되지만 set 수행시 연결되지 않고,
set aaa bbb
# 이미 저장된 값을 get 수행하면 moved 로 
# redis pod 로 redirect 시도하고 연결되지 않는다.
get aaa
moved xxxx

# 로컬에서 redis set,get 등 수행시 해당 값을 redis node(slot)으로 분배를 시도하고
# 결국 redis-cluster 의 pod(redis node) ip 에 접근할 수 밖에 없다.

# 해결 방법은 redis-cluster 를 프록시 해주는 redis-cluster-proxy 프로그램을
# k8s service(+pod)에 두고, 이 redis-cluster-proxy 로 요청을 하도록 한다.

# 먼저 redis-cluster-proxy 도커 이미지를 생성한다.
# os 버전이 낮아 gcc 버전이 낮으면 빌드 에러가 발생하니 최신 os 기반에서 빌드하자.
# 자세한 내용은 dockerfile 참고

# 이미 빌드된 redis-cluster-proxy 도커 이미지 사용시 참고


# 이제 redis-cluster-proxy 를 k8s service(+pod)로 다음과 같이 구성한다.
# redis-cluster-proxy.yaml
apiVersion: v1
kind: Pod
metadata:
  name: redis-cluster-proxy
  labels:
    app: redis-cluster-proxy
spec:
  containers:
    - name: redis-cluster-proxy
      image: ysoftman/redis-cluster-proxy:latest
      imagePullPolicy: Always
      command:
        ["/redis-cluster-proxy/src/redis-cluster-proxy", "10.123.123.123:6379"]
---
apiVersion: v1
kind: Service
metadata:
  name: redis-cluster-proxy
  labels:
    app: redis-cluster-proxy
spec:
  # type: ClusterIP
  type: NodePort
  ports:
    - port: 7777
      targetPort: 7777
      nodePort: 30777 # The range of valid ports is 30000-32767
      name: redis-cluster-proxy
  selector:
    app: redis-cluster-proxy

# k8s service(+pod) 반영
kubectl apply -f redis-cluster-proxy.yaml --namespace redis

# 다음과 같은 요청 흐름이 된다.
로컬 redis-cli k8s 노드 중 하나:30777 --> redis-cluster-proxy(service) --> redis-cluster-proxy(pod):7777 --> redis cluster nodes(pods):6379

# 이제 로컬 개발시에는 redis-cluster-proxy 를 통해 k8s redis 를 사용할 수 있다.
redis-cli -h {k8s 노드 중 하나} -p 30777 -c


#####


# helm 으로 외부에서 접근 가능한 redis-cluster 으로 구성할 경우
# 다음과 같이 실행하면 service 3개에 각각 redis pod 1개를 띄우고, 
# 서비스별 external ip 를 생성한다.(시간이 좀 걸린다.)
helm install redis-cluster bitnami/redis-cluster \
--namespace redis-cluster \
--set cluster.node=3 \
--set cluster.externalAccess.enabled=true

# 이후 helm upgrade 설치 가이드 명령 참고해서 
helm upgrade redis-cluster bitnami/redis-cluster \
--namespace redis-cluster \
--set cluster.node=3 \
--set cluster.externalAccess.enabled=true \
--set cluster.externalAccess.service.type=LoadBalancer \
--set "cluster.externalAccess.service.loadBalancerIP[0]=10.10.10.1,cluster.externalAccess.service.loadBalancerIP[1]=10.10.10.2,cluster.externalAccess.service.loadBalancerIP[2]=10.10.10.3"


# 참고


redis cluster in kubernetes

# kubernetes(k8s) 노드가 다음과 같이 구성되어 있다고 가정하고 설치한다.
1 maser
3 worker

# 참고
https://kubernetes.io/ko/docs/concepts/workloads/controllers/statefulset/
https://kubernetes.io/ko/docs/tutorials/configuration/configure-redis-using-configmap/
https://github.com/sanderploegsma/redis-cluster


# redis-cluster.yaml 내용
apiVersion: v1
kind: Namespace
metadata:
  name: redis-cluster
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-cluster
  labels:
    app: redis-cluster
data:
  fix-ip.sh: |
    #!/bin/sh
    CLUSTER_CONFIG="/data/nodes.conf"
    if [ -f ${CLUSTER_CONFIG} ]; then
      if [ -z "${POD_IP}" ]; then
        echo "Unable to determine Pod IP address!"
        exit 1
      fi
      echo "Updating my IP to ${POD_IP} in ${CLUSTER_CONFIG}"
      sed -i.bak -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${CLUSTER_CONFIG}
    fi
    exec "$@"
  # | (newline 유지하는 멀티라인)
  # + (마지막 newline 유지)
  redis.conf: |+
    cluster-enabled yes
    cluster-require-full-coverage no
    cluster-node-timeout 15000
    cluster-config-file /data/nodes.conf
    cluster-migration-barrier 1
    appendonly no
    save ""
    protected-mode no
    requirepass "password123"
    masterauth "password123"

---

apiVersion: v1
kind: Service
metadata:
  name: redis-cluster
  labels:
    app: redis-cluster
spec:
  ports:
  - port: 6379
    targetPort: 6379
    name: client
  - port: 16379
    targetPort: 16379
    name: gossip
  # clusterIP 로 k8s 클러스터내부에서만 접근 가능한 Service(pod묶음)을 제공하자.
  type: clusterIP
  # clusterIP 를 명시하지 않으면 Service 시작시 IP 가 자동할당된다.
  #clusterIP: None
  clusterIP: "10.10.10.123"
  selector:
    app: redis-cluster
---
# StatefulSet 은 Pod 집합인 Deployment 와 스케일
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
  labels:
    app: redis-cluster
spec:
  serviceName: redis-cluster
  replicas: 4
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      labels:
        app: redis-cluster
    spec:
      containers:
      - name: redis
        image: redis:6.2-rc
        args: ["--requirepass", "password123"]
        ports:
        - containerPort: 6379
          name: client
        - containerPort: 16379
          name: gossip
        command: ["/conf/fix-ip.sh", "redis-server", "/conf/redis.conf"]
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - "redis-cli -h $(hostname) ping"
          initialDelaySeconds: 15
          timeoutSeconds: 5
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - "redis-cli -h $(hostname) ping"
          initialDelaySeconds: 20
          periodSeconds: 3
        env:
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        volumeMounts:
        - name: conf
          mountPath: /conf
          readOnly: false
        - name: data
          mountPath: /data
          readOnly: false
      volumes:
      - name: conf
        configMap:
          name: redis-cluster
          defaultMode: 0755
  volumeClaimTemplates:  #  PersistentVolumesClaims(PVC) 100MiB 요청(생성)해서 pod 가 내려가도 데이터는 유지될 수 있도록 한다.
  - metadata:
      name: data
      labels:
        name: redis-cluster
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 100Mi

# redis 클러스터 master, worker, statefulset, service 생성
kubectl apply -f redis-cluser.yaml

# configmap, statefulset, service 확인
kubectl describe cm --namespace redis-cluster
kubectl describe sts --namespace redis-cluster
kubectl describe svc --namespace redis-cluster

# statefulset 에서 PersistentVolumeClaim(PVC) 상태 확인
kubectl get pvc --namespace redis-cluster

# POD 및 서비스 상태 확인
kubectl get all --namespace redis-cluster

# 클러스터링 구성
# redis5 부터 redis-cli 에서 redis-trib.rb 의 기능을 사용할 수 있다.
# redis 클러스터 명령 참고
redis-cli --cluster help

# redis 동작중인 pod 파악
kubectl get pods --namespace redis-cluster | grep redis | awk '{print $1}' | head -1

# jsonpath output 을 app=redis 인 pod 들의 IP 파악
# 참고 https://kubernetes.io/docs/reference/kubectl/jsonpath/
kubectl get pods --namespace redis-cluster -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}{":6379 "}{end}'

# pod ip:port 를 옵션으로 주어 클러스터링을 구성한다.
# cluster-replicas 복제(슬레이브) 개수 4개의 노드라면 2개 마스터, 2개 슬레이브가 된다.
kubectl --namespace redis-cluster \
exec -it redis-cluster-0 -- \
redis-cli --cluster create --cluster-replicas 1 -a "password123" \
$(kubectl --namespace redis-cluster get pods -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}{":6379 "}{end}')
# Can I set the above configuration? (type 'yes' to accept): yes 입력

# redis cluster info 확인
kubectl --namespace redis-cluster exec -it redis-cluster-0 -- redis-cli -a "password123" cluster info

# redis cluster node 확인
kubectl --namespace redis-cluster exec -it redis-cluster-0 -- redis-cli -a "password123" -c cluster nodes

# redis-cluster-0 파드에서 redis-cli 로 clusterIP(고정) 에 접속해 테스트
kubectl --namespace redis-cluster exec -it redis-cluster-0 -- redis-cli -h 10.10.10.123 -p 6379 -c -a "password123"
10.10.10.123:6379> set aaa lemon
OK
10.10.10.123:6379> get aaa
"lemon"
10.10.10.123:6379> set bbb apple
-> Redirected to slot [5287] located at 10.10.123.100: 6379
OK
10.10.123.100:6379> get bbb
"apple"


####


# 노드 변경이 필요한 경우
# replicas=6 로 노드(pod) 6개로 늘린다.
# 기존보다 작으면 줄어든다. 줄일때는 노드 제거후 적용
kubectl --namespace redis-cluster scale statefulset redis-cluster --replicas=6

# 2추가된 노드에
# 10.10.10.10:6379 기존 존재하는 클러스터 노드에 마스터 노드 추가
kubectl --namespace redis-cluster \
exec -it redis-cluster-0 -- \
redis-cli -a "password123" --cluster add-node 10.10.10.11:6379 10.10.10.10:6379

# 10.10.10.11:6379 마스터의 슬레이브가 추가
kubectl --namespace redis-cluster \
exec -it redis-cluster-0 -- \
redis-cli -a "password123" --cluster add-node 10.10.10.12:6379 10.10.10.11:6379 --cluster-slave

# 슬롯 재분배
# 새 마스터 노드가 추가 된경우 --cluster-use-empty-masters 사용
kubectl --namespace redis-cluster \
exec -it redis-cluster-0 -- \
redis-cli -a "password123" --cluster rebalance 10.10.10.10:6379 --cluster-use-empty-masters

# 노드 빼는 경우(10.10.10.10:6379 노드에 접속해서 aaaaabbbbb 노드들 삭제)
kubectl --namespace redis-cluster \
exec -it redis-clustqer-0 -- \
redis-cli -a "password123" --cluster del-node 10.10.10.12:6379 aaaaabbbbb


####


# confimap 삭제
kubectl delete cm redis-cluster --namespace redis-cluster

# PersistentVolumeClaim(PVC) 삭제
kubectl delete sts redis-cluster --namespace redis-cluster

# pvc 삭제
# kubectl get pvc 로 볼륨이름 파악
kubectl delete pvc 볼륨이름 --namespace redis-cluster
# 또는 전체 삭제하는 경우
kubectl delete pvc --all --namespace redis-cluster

# service 모두 삭제
kubectl delete service --all --namespace redis-cluster

# pod 모두 삭제
kubectl delete pods --all --namespace redis-cluster

# unknown state pod 가 삭제 안되는 경우
kubectl delete pods --all --grace-period=0 --force --wait=false --namespace redis-cluster

# 네임스페이의 모든 리소스 삭제(단 secret,configmap,roels등과 같은 특정 리소스는 명시적으로 삭제해야 한다.)
# all=pods,deployments,rs 등을 의미한다.
kubectl delete all --all --namespace redis-cluster

# namespace 삭제
kubectl delete ns redis-cluster

Redis 시작하기

# 소스로 설치
# Redis 다운 받기(윈도우는 비공식적으로 지원하지만 불안정하다고 한다.)
# wget http://redis.googlecode.com/files/redis-2.6.14.tar.gz
tar zxvf redis-2.6.14.tar.gz
cd redis-2.6.14

# /deps/jemalloc/lib/libjemalloc.a 찾을 수 없다는 에러가 발생하면
# make distclean 후 make
make
sudo make install

# Redis 2.6 버전 make 실행시 다음과 같은 에러 발생하는 경우가 있다.
/usr/local/redis/src/zmalloc.c:223: undefined reference to `__sync_add_and_fetch_4'

# 현재 cpu 설정이 맞지 않아 발생한 것으로 우선 uname 으로 자신 cpu 타입을 확인한다.
uname -a

# i686 인 경우 다음과 같이 make 설정을 변경하고 make 하자
vi src/.make-settings
OPT=-O2 -march=i686

##########

# 2018-02 현재 4.0 을 사용
wget http://download.redis.io/releases/redis-4.0.8.tar.gz
tar zxvf redis-4.0.8.tar.gz
cd redis-4.0.8
make
sudo make install

##########

# redis 소스에 redis-4.0.8/src/redis-trib.rb 로 클러스터를 설정한다.
# redis-trib.rb 를 사용하기 위해 최신 버전의 ruby 설치
wget https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.0.tar.gz
tar zxvf ruby-2.5.0.tar.gz
cd ruby-2.5.0
./configure
make
sudo make install

# gem(ruby)에서 사용할 redis 설치
sudo gem install redis

##########

# Redis 서버 실행
redis-server

# Redis 설정 파일로 실행
redis-server /etc/redis.conf

# Redis 서버 데몬으로 실행, 보호모드 비활성화
# 보호모드가 활성화 되면 로컬외 외부 클라이언트가 shutdown 할수 없음.
redis-server --daemonize yes --protected-mode no

# 기본 redis.conf 복사
sudo /etc/redis.conf ./
chown ysoftman:ysoftman ./redis.conf

# 클러스터 구성을 위해서 최소 3개의 노드(redis-server 인스턴스)가 있어야 한다.
# 포트 설정 별로 디렉토리 생성
mkdir 7001 7002 7003

##########

# cluster 구성
vi redis-7001.conf
port 7001
# bind ip 변경
# 원격으로 접속한다면 실제 IP 를 추가하자.
# 127.0.0.1 을 처음으로 명시하면 redis-server 가 127.0.0.1 으로 시작되어 cluster 생성시 원격 노드 조인 작업이 끝나지 않는다.
# 관련 이슈 https://github.com/antirez/redis/issues/1703#issuecomment-369822404
bind 10.10.10.1 127.0.0.1

# 클러스터 활성화
cluster-enabled yes

# 클러스터 노드 상태를 기록하는 파일로 노드가 자동 생성하고 사용자 수정하면 안된다.
cluster-config-file /home/ysoftman/7001/nodes-7001.conf

# 클러스터 노드 타임아웃 : 단위는 ms, 노드가 살아있는지/내려갔는지 체크 
cluster-node-timeout 15000

# 워킹 디렉토리 설정
dir /home/ysoftman/7001
# 로그 파일 위치
logfile /home/ysoftman/7001/redis_7001.log
# pid 파일 위치
pidfile /home/ysoftman/7001/redis_7001.pid
# redis 는 다음 2가지 모드로 파일로 백업한다.

# append 모드 : 노드가 내려갔다 다시 시작할때 데이터를 추가하는 방식으로 설정
appendonly yes

# rdb 모드 : 파일명(경로가 아닌 파일명만 명시해야 한다. 경로는 dir 로 설정된 곳을 사용한다.)
dbfilename dump_7001.rdb
# append 모드 비활성화
appendonly no
# rdb 모드 비활성화
save ""

##########

# 위 설정으로 포트별로 디렉토리에 복사하고 포트별로 redis-server 시작
./bin/redis-server ./7001/redis-7001.conf
./bin/redis-server ./7002/redis-7002.conf
./bin/redis-server ./7003/redis-7003.conf

http://redisgate.kr/redis/cluster/redis-trib.php
# 별도의 장비(10.10.10.2)도 위처럼 설정하여 클러스터의 노드로 추가할 수 있다.
# slave 노드는 master 내용을 복제해두며 replicas 로 설정할 수 있다.
# --replicas n 으로 master 당 사용할 slave 개수를 지정한다.
# 그러면 현재 노드들에서 적절한 master - slave 를 구성한다.
# 디폴트는 --replicas 0 으로 모든 노드가 master 가 된다.
# echo yes 는 (type 'yes' to accept) 를 자동 입력하기 위해 사용
echo yes | ./redis-4.0.8/src/redis-trib.rb create --replicas 1 10.10.10.1:7001 10.10.10.1:7002 10.10.10.1:7003 10.10.10.2:7001 10.10.10.2:7002 10.10.10.2:7003

# 10.10.10.1:7001 노드에 10.10.10.1:7004 노드 master 로 추가
redis-trib.rb add-node 10.10.10.1:7004 10.10.10.1:7001

# slave 로 추가시
redis-trib.rb add-node --slave 10.10.10.1:7004 10.10.10.1:7001

# 10.10.10.1:7004 노드 삭제
redis-trib.rb del-node 10.10.10.1:7004 노드_ID

# ERR Slot 0 is already busy (Redis::CommandError) 에러 발생시
# cluster 를 다시 시작할 경우 기존 .rdb node*.conf .aof 파일은 삭제해야 한다.
# redis 시작시 설정에 따라 .rdb 또는 .aof 파일로 복구를 시도하면 에러가 발생할 수 있으니 필요없다면 삭제하도록 한다.
find . -name dump*.rdb -exec rm -rfv {} \;
find . -name nodes-*.conf -exec rm -rfv {} \;
find . -name *.aof -exec rm -rfv {} \;

##########

# redis 5.0 부터는 redis-cli 에서 redis-trib.rb 의 기능을 사용할 수 있다.
# Redis 동작 확인
redis-cli -h 10.10.10.1 -p 7001 ping

# 클러스터를 사용하는 경우 -c 옵션 사용
# moved x 는 호스트x에 데이터가 저정되어 있다는 의미고
# ask x 는 호스트x에 다시 물어(질의)야 한다는 의미다.
# -c 는 moved, ask 대상을 따라가서 (질의하게) 된다.
redis-cli -h 10.10.10.1 -p 7001 -c

# 키 scan
redis-cli -h 10.10.10.1-p 7001 -c --scan

# 특정패턴의 키 scan
redis-cli -h 10.10.10.1-p 7001 -c --scan --pattern "*ysoftman"

# 또는 다음처럼 접속해서 커맨드만 실행시켜 끝낼 수도 있다.
redis-cli -h 10.10.10.1 -p 7001 -c cluster info

# 노드 정보(myself 표시는 현재 접속한 노드), ip 로 정렬해서 보자.
redis-cli -h 10.10.10.1 -p 7001 -c cluster nodes | sort -k 2

# 노드 정보(myself 표시는 현재 접속한 노드)
# slave 에 master 노드 id 가 명시되어있어
# master-slave 연결 순서로 정렬해서 보자.
redis-cli -h 10.10.10.1 -p 7001 -c cluster nodes | sort -k 4
# 노드별 할당된 슬롯 정보
redis-cli -h 10.10.10.1 -p 7001 -c cluster slots

# ysoftman으로 시작하는 키만 노드에서 삭제하기
# 각 노드에 del 커맨드를 실행해야 한다.
# del 는 정규식이나 와일드카드를 사용할수 없고 exact 키 매칭이 되야 한다.
# 따라서 scan, pattern 으로 키이름을 파악해 xargs 로 넘겨야 한다.
# 삭제시 에러가발생하면 조회한 key를 파일로 저장해 하나씩 삭제하는 스크립트를 작성하자.
redis-cli -h 10.10.10.1 -p 7001 -c --scan --pattern "ysoftman*" | xargs redis-cli -h 10.10.10.1 -p 7001 -c del
redis-cli -h 10.10.10.1 -p 7002 -c --scan --pattern "ysoftman*" | xargs redis-cli -h 10.10.10.1 -p 7002 -c del
redis-cli -h 10.10.10.1 -p 7003 -c --scan --pattern "ysoftman*" | xargs redis-cli -h 10.10.10.1 -p 7003 -c del

##########

# 클러스터 정보 확인
redis>cluster info

# 클라이언트에서 set
redis>set nickname ysoftman

# 클라이언트에서 get
redis>get nickname

# Redis 서버 종료
# protected-mode 가 비활성화된 redis-server 만 가능
redis>shutdown

# 또는 각 서버 redis-cli 로 종료
redis-cli -h 10.10.10.1 -p 7001 shutdown
redis-cli -h 10.10.10.1 -p 7002 shutdown
redis-cli -h 10.10.10.1 -p 7003 shutdown

##########

# 장애 복구 과정(failover)
# 10.10.10.1:7001 master 노드가 죽었을때(kill -9 PID)
# 10.10.10.1:7002 slave 노드를 master 로 변환
redis-cli -h 10.10.10.1 -p 7002 -c cluster failover

# 10.10.10.1:7001 master 죽은 노드를 클러스터에서 제거
# 60초 안에 모든 노드들에서 forget 을 실행주지 않으면 정상 노드가
# 연결을 시도하기 때문에 죽은 노드가 handshake 상태가 된다.
# handshake 상태의 죽은 노드는 계속해서 id 가 변경된다.
# 다음과 같이 한번에 살아 있는 노드에서 죽은 노드를 제거해야 한다.
# 죽은 노드가 n개라면 n번만큰 살아 있는 노드에서 forget 해야 한다.
redis-cli -h 10.10.10.1 -p 7002 -c cluster forget 죽은_노드_ID
redis-cli -h 10.10.10.1 -p 7003 -c cluster forget 죽은_노드_ID
... 여러 노드에서 죽은 노드 만큼 수행

# 계속 변하는 handshake 노드도 다음의 쉘 스크립트로 한번에 정리할 수 있다.
https://github.com/antirez/redis/issues/2965#issuecomment-233779778
# 죽은 노드를 정리하고 클러스터 상태를 보면
# 죽은 노의 슬롯들이 처리되지 않아 클러스터 상태가 fail 로 나온다.
redis-cli -h 10.10.10.1 -p 7001 -c cluster nodes
cluster_state:fail

# 죽은 노드가 관리하던 슬롯(nodes 정보로 봤을때 마지막 필드에 나온 숫자-숫자)
# 참고로 슬롯범위를 알지 못할때 실패 슬롯 개수를 파악하고
# 노드들을 slots 로 정렬하고 연속적이지 않은 부분이나, 끝이
# cluster_slots_fail 개수 만큼이 범위가 된다.
redis-cli -h 10.10.10.1 -p 7001 -c cluster info | grep cluster_slots_fail
redis-cli -h 10.10.10.1 -p 7001 -c cluster nodes | sort -k 9

# 슬롯들을 7001 에 추가(이관)해준다.
# 위에서 죽은 노드를 빼줘야지 슬롯을 이관할 수 있다.
# 참고로 {a..b} 범위는 쉘 명령으로 스크립트파일.sh 을 만들어 사용하는 경우
# 아래 명령줄 앞에 eval 을 사용해야 한다.

redis-cli -h 10.10.10.1 -p 7001 -c cluster addslots {10000..12000}
# 노드를 다시 추가할 경우
# redis 노드 시작
./bin/redis-server ./7003/redis-7003.conf

# 신규 노드가 기존 노드(ip로 명시해야 한다.)를 meet 하도록 한다.
redis-cli -h 10.10.10.1 -p 7003 -c cluster meet 10.10.10.1 7001

# addslot 대신 reshard 로 슬롯을 재분배 할 수 도 있다.
# redis 4.x 는 redis-trib.rb rehsard 사용
redis-cli -h 10.10.10.1 -p 7001 -c cluster reshard