5 분 소요

Redis Cluster에 구축방법을 작성한다. 하나의 인스턴스로 레디스는 작동하여 보았지만 클러스터 모드는 처음 접한다.


Redis의 작동모드

Standalone

가장 기본적인 형태. 레디스 하나를 실행하여 사용한다.

Master-Slave

읽고/쓰기를 담당하는 마스터와 읽기만을 담당하는 슬레이브가 있어서 서로 상호보완한다.

Master-Slave-Sentinel

센티널 서버는 일종의 레디스 전용 모니터링 서버. 마스터-슬레이브와 같지만 센티널서버가 있어서 마스터 서버가 다운되면 슬레이브 서버를 마스터 서버로 변경해준다. 센티널 서버 역시 단일로 구성할 수도 있고 여러대를 구성할 수도 있다.

Cluster

센티널 서버가 없는 대신, 데이터를 여러 마스터에 샤딩하고 각 마스터에 레플리카를 붙여 고가용성을 구현한다.

최소 요건은 마스터 3대다. 레플리카는 필수가 아니지만, 마스터 하나가 죽었을 때 자동 페일오버를 하려면 있어야 하므로 실운영에서는 마스터 3 + 레플리카 3 = 6개 노드를 권장 구성으로 본다. 여기서 말하는 것은 서버 대수가 아니라 노드(프로세스) 수다. 이 글처럼 한 대에서 포트만 나눠 6개를 띄울 수도 있다.

마스터가 3대 이상이어야 하는 이유는 페일오버 판정을 과반수 투표로 하기 때문이다. 2대면 과반수가 성립하지 않는다.

2026년 수정 안내 이 글에는 해시 슬롯 할당 단계가 빠져 있었다. 슬롯을 배정하지 않으면 클러스터 상태가 fail이라 키를 하나도 처리하지 못한다. 아래에 해당 단계를 추가했고, 지금은 훨씬 간단한 redis-cli --cluster create 방식이 있으므로 그쪽을 먼저 소개한다.


Redis Cluster 구성


conf 파일 작성

redis-5001.conf 파일에서

port 5001
cluster-enabled yes
cluster-config-file /home/centos/redis/redis-cluster/node-5001.conf
cluster-node-timeout 3000
dir "/home/centos/redis/redis-cluster/node-5001/data"
appendonly yes

형식으로 클러스터를 활성화한다.

마스터, 슬레이브 상관 없이 모두 다 같은 형식의 설정으로 사용한다. 설정 내용 중에 있는 node-5001.conf 파일은 존재하지 않지만 이 설정대로 레디스를 실행하고 나면 파일이 자동으로 생성되게 된다.


권장 : redis-cli –cluster create

Redis 5부터는 아래 명령 하나로 노드 등록·슬롯 할당·레플리카 배정이 한 번에 끝난다. 특별한 이유가 없다면 이 방법을 쓰면 된다.

redis-cli --cluster create \
  127.0.0.1:5001 127.0.0.1:5002 127.0.0.1:5003 \
  127.0.0.1:5004 127.0.0.1:5005 127.0.0.1:5006 \
  --cluster-replicas 1

앞의 3개가 마스터가 되고 뒤의 3개가 각각 레플리카로 붙는다. 16384개의 해시 슬롯도 자동으로 3등분된다.

아래는 이 과정을 수동으로 하나씩 밟는 방법이다.


노드 등록

설치 완료 후 redis-cli 를 이용해 제일 첫번째 노드에 다른 노드들을 등록시킨다.

redis-cli -h 127.0.0.1 -p 5001 cluster meet 127.0.0.1 5002
(...중략...)
redis-cli -h 127.0.0.1 -p 5001 cluster meet 127.0.0.1 5006

마지막으로 cluster nodes 명령으로 등록된 노드들을 확인한다.

[centos@ip-172-26-7-248 redis]$ redis-cli -h 127.0.0.1 -p 5001 cluster nodes
94fefe320dbbdc2e4cc9ed97ad6971931e8a9dfb 127.0.0.1:5003@15003 master - 0 1572367588563 2 connected
14b561a8f9d3e2dbb17e6a0e1cdaad0b9e4cb959 127.0.0.1:5005@15005 master - 0 1572367587561 4 connected
2c5ca8b0dec7afda81d1805a7aa6aa3c8c4de81c 127.0.0.1:5002@15002 master - 0 1572367588061 1 connected
167aaddf91854a71fe46fda8694be96810c2fdbb 127.0.0.1:5004@15004 master - 0 1572367588061 3 connected
44cc12a6792b43cd5fc964f0693dbac5ffaaecc3 127.0.0.1:5006@15006 master - 0 1572367588563 5 connected
e0c5da84dec4deb5578406b8e1d2dd1ff71cd012 127.0.0.1:5001@15001 myself,master - 0 1572367588000 0 connected
[centos@ip-172-26-7-248 redis]$

해시 슬롯 할당 (빠뜨리면 안 되는 단계)

Redis Cluster는 키를 16384개의 해시 슬롯에 나눠 담는다. CRC16(key) % 16384로 슬롯을 정하고, 각 슬롯은 특정 마스터가 담당한다.

cluster meet으로 노드들을 서로 인식시키기만 해서는 어느 마스터도 슬롯을 갖고 있지 않다. 이 상태에서는 cluster infocluster_statefail이고, 어떤 키도 읽거나 쓸 수 없다.

마스터로 쓸 3개 노드에 슬롯을 나눠 배정한다.

redis-cli -h 127.0.0.1 -p 5001 cluster addslots $(seq 0 5460)
redis-cli -h 127.0.0.1 -p 5002 cluster addslots $(seq 5461 10922)
redis-cli -h 127.0.0.1 -p 5003 cluster addslots $(seq 10923 16383)

할당 후 상태를 확인한다.

redis-cli -h 127.0.0.1 -p 5001 cluster info

cluster_state:okcluster_slots_assigned:16384가 나와야 정상이다.

cluster nodes 출력에서도 마스터 뒤에 담당 슬롯 범위가 붙어야 한다.

e0c5da84... 127.0.0.1:5001@15001 myself,master - 0 ... connected 0-5460
2c5ca8b0... 127.0.0.1:5002@15002 master - 0 ... connected 5461-10922
94fefe32... 127.0.0.1:5003@15003 master - 0 ... connected 10923-16383

이 글에 처음 올렸던 출력에는 이 슬롯 범위가 없었는데, 그게 바로 클러스터가 아직 동작하지 않는 상태였다는 뜻이다.


Slave 노드 등록

redis-cli 명령으로 슬레이브 노드를 마스터 노드에 등록한다.

redis-cli -h [슬레이브노드IP] -p [슬레이브노드포트] cluster replicate [붙어야할 마스터 노드ID]

마스터 노드ID는 nodes 명령으로 볼 수 있다.

[centos@ip-172-26-7-248 redis]$ redis-cli -h 127.0.0.1 -p 5004 cluster replicate e0c5da84dec4deb5578406b8e1d2dd1ff71cd012
17947:S 30 Oct 01:56:19.575 * Before turning into a slave, using my master parameters to synthesize a cached master: I may be able to synchronize with the new master with just a partial transfer.
OK
[centos@ip-172-26-7-248 redis]$ 17947:S 30 Oct 01:56:20.273 * Connecting to MASTER 127.0.0.1:5001
17947:S 30 Oct 01:56:20.273 * MASTER <-> SLAVE sync started
17947:S 30 Oct 01:56:20.273 * Non blocking connect for SYNC fired the event.
17947:S 30 Oct 01:56:20.273 * Master replied to PING, replication can continue...
17947:S 30 Oct 01:56:20.273 * Trying a partial resynchronization (request c34e3c02004a4c8e06fcb47bc77ea45f138c7512:1).
17863:M 30 Oct 01:56:20.273 * Slave 127.0.0.1:5004 asks for synchronization
17863:M 30 Oct 01:56:20.273 * Partial resynchronization not accepted: Replication ID mismatch (Slave asked for 'c34e3c02004a4c8e06fcb47bc77ea45f138c7512', my replication IDs are 'c7d75434e77299659d54bb0826287f9f97ac9f17' and '0000000000000000000000000000000000000000')
17863:M 30 Oct 01:56:20.273 * Starting BGSAVE for SYNC with target: disk
17863:M 30 Oct 01:56:20.274 * Background saving started by pid 22762
17947:S 30 Oct 01:56:20.274 * Full resync from master: 5ed80233221922dec0393de2100c4d48903d1a70:0
17947:S 30 Oct 01:56:20.274 * Discarding previously cached master state.
22762:C 30 Oct 01:56:20.278 * DB saved on disk
22762:C 30 Oct 01:56:20.278 * RDB: 0 MB of memory used by copy-on-write
17863:M 30 Oct 01:56:20.368 * Background saving terminated with success
17863:M 30 Oct 01:56:20.368 * Synchronization with slave 127.0.0.1:5004 succeeded
17947:S 30 Oct 01:56:20.368 * MASTER <-> SLAVE sync: receiving 176 bytes from master
17947:S 30 Oct 01:56:20.368 * MASTER <-> SLAVE sync: Flushing old data
17947:S 30 Oct 01:56:20.368 * MASTER <-> SLAVE sync: Loading DB in memory
17947:S 30 Oct 01:56:20.368 * MASTER <-> SLAVE sync: Finished with success
17947:S 30 Oct 01:56:20.369 * Background append only file rewriting started by pid 22763
17947:S 30 Oct 01:56:20.393 * AOF rewrite child asks to stop sending diffs.
22763:C 30 Oct 01:56:20.393 * Parent agreed to stop sending diffs. Finalizing AOF...
22763:C 30 Oct 01:56:20.393 * Concatenating 0.00 MB of AOF diff received from parent.
22763:C 30 Oct 01:56:20.393 * SYNC append only file rewrite performed
22763:C 30 Oct 01:56:20.394 * AOF rewrite: 0 MB of memory used by copy-on-write
17947:S 30 Oct 01:56:20.473 * Background AOF rewrite terminated with success
17947:S 30 Oct 01:56:20.473 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
17947:S 30 Oct 01:56:20.473 * Background AOF rewrite finished successfully

[centos@ip-172-26-7-248 redis]$

최종적으로 다음과 같은 형태가 된다.

[centos@ip-172-26-7-248 redis]$ redis-cli -h 127.0.0.1 -p 5001 cluster nodes
94fefe320dbbdc2e4cc9ed97ad6971931e8a9dfb 127.0.0.1:5003@15003 master - 0 1572368364897 2 connected
14b561a8f9d3e2dbb17e6a0e1cdaad0b9e4cb959 127.0.0.1:5005@15005 slave 2c5ca8b0dec7afda81d1805a7aa6aa3c8c4de81c 0 1572368365599 4 connected
2c5ca8b0dec7afda81d1805a7aa6aa3c8c4de81c 127.0.0.1:5002@15002 master - 0 1572368365599 1 connected
167aaddf91854a71fe46fda8694be96810c2fdbb 127.0.0.1:5004@15004 slave e0c5da84dec4deb5578406b8e1d2dd1ff71cd012 0 1572368365599 3 connected
44cc12a6792b43cd5fc964f0693dbac5ffaaecc3 127.0.0.1:5006@15006 slave 94fefe320dbbdc2e4cc9ed97ad6971931e8a9dfb 0 1572368364597 5 connected
e0c5da84dec4deb5578406b8e1d2dd1ff71cd012 127.0.0.1:5001@15001 myself,master - 0 1572368364000 0 connected
[centos@ip-172-26-7-248 redis]$

클러스터를 쓸 때 알아둘 점

  • 여러 키를 한 번에 다루는 명령은 같은 슬롯에 있어야 한다. MGET a b c처럼 여러 키를 쓰는 명령은 세 키가 모두 같은 슬롯일 때만 동작한다. 일부러 같은 슬롯에 모으려면 해시 태그를 쓴다. user:{1000}:nameuser:{1000}:level은 중괄호 안의 1000만으로 슬롯을 계산하므로 같은 노드에 들어간다.
  • 클라이언트가 클러스터를 지원해야 한다. 노드가 자기 슬롯이 아닌 키를 받으면 MOVED 응답으로 리다이렉트하는데, 클러스터 모드를 모르는 클라이언트는 이걸 에러로 처리한다.
  • redis-cli로 접속할 때는 -c 옵션을 붙여야 리다이렉트를 따라간다.

    redis-cli -c -h 127.0.0.1 -p 5001
    
  • SELECT로 DB를 바꾸는 기능은 클러스터 모드에서 쓸 수 없다. 0번 DB만 존재한다.

댓글 남기기