19 분 소요

Cluster 구축 :

설계한 Redis Cluster를 직접 구축해 보겠다.

1. Redis 설치

  • 먼저 Redis를 각 서버에 stable 버전으로 설치한다.
    • root 계정에 sudo apt install을 사용하여 설치하는 것보다 하위 계정에 직접 설치하는 것이 파일을 컨트롤하기 쉽다.
    • sudo apt install로 설치하면 /opt/redis/ 경로에 redis 파일들이 있다.
    • wget 로 설치하면 설치한 계정에 redis-stable 폴더에 redis 파일들이 있다.
$ sudo apt-get update
$ sudo apt-get upgrade
$ wget http://download.redis.io/redis-stable.tar.gz
$ tar xvzf redis-stable.tar.gz
$ cd redis-stable
~/redis-stable$ sudo apt install make
make
---
# 다음과 같은 에러 발생 시
/bin/sh: 1: cc: not found
make[1]: *** [Makefile:403: adlist.o] Error 127

sudo apt install gcc
make distclean
make
---
~/redis-stable$ sudo make install

# 테스트 해보기
redis-server
ps -ef | grep redis

# 설치 버전 확인 (version : 7.0.5)
redis-cli info

# 종료
redis-cli shutdown

2. 싱글 서버

여러 서버에 Cluster 구축해보기 전에 테스트로 하나의 서버에 Cluster를 구축해 보겠다.

2.1. 기본 세팅

1) 폴더 생성

  • redis-stable 폴더에서 redis.conf 파일을 작업할 폴더에 복사해서 가져온다.
sudo mkdir /home/ubuntu/redis-test
sudo cp ~/redis-stable/redis.conf ~/redis-test/redis.conf
cd redis-test

# 필요 시 폴더 및 하위 파일들에 대한 사용 그룹 및 권한 변경
$ sudo chown -R ubuntu:ubuntu redis-test
$ sudo chmod -R g+wx redis-test

2) 설정 파일 수정

  • 아래와 같이 7300.conf, 7301.conf, 7302.conf 파일을 만들어준다.
# Master conf
sudo cp ~/redis-test/redis.conf ~/redis-test/7300.conf
sudo vim ~/redis-test/7300.conf
---
daemonize yes
port 7300
pidfile /home/ubuntu/redis-test/test/redis_7300.pid
logfile /home/ubuntu/redis-test/test/redis-7300.log
dir /home/ubuntu/redis-test/test/7300

#requirepass [thisispassword]
#masterauth [thisispassword]

cluster-config-file node-7300.conf
cluster-enabled yes
--- :wq!
  • 아래와 같이 7400.conf, 7401.conf, 7402.conf 파일을 만들어준다.
# Replica conf
sudo cp ~/redis-test/redis.conf ~/redis-test/7400.conf
sudo vim ~/redis-test/7400.conf
---
위와 동일하게 포트번호만 변경해서 작성
--- :wq!

2.2. 노드 실행

# 모든 노드 실행
# server1
sudo redis-server /home/ubuntu/redis-test/7300.conf
sudo redis-server /home/ubuntu/redis-test/7402.conf

# server2
redis-server /home/ubuntu/redis-test/7301.conf
redis-server /home/ubuntu/redis-test/7400.conf

# server3
redis-server /home/ubuntu/redis-test/7302.conf
redis-server /home/ubuntu/redis-test/7401.conf

# 실행 중인 redis 프로세스 확인
ps -ef | grep redis
root        9650       1  0 16:18 ?        00:00:13 redis-server 0.0.0.0:6300 [cluster]
root        9657       1  0 16:18 ?        00:00:07 redis-server 0.0.0.0:6402 [cluster]
root        9666       1  0 16:18 ?        00:00:07 redis-server 0.0.0.0:6301 [cluster]
root        9673       1  0 16:18 ?        00:00:07 redis-server 0.0.0.0:6400 [cluster]
root        9680       1  0 16:18 ?        00:00:15 redis-server 0.0.0.0:6302 [cluster]
root        9687       1  0 16:19 ?        00:00:07 redis-server 0.0.0.0:6401 [cluster]
ubuntu      9773    9513  0 16:52 pts/0    00:00:00 grep --color=auto redis

# 노드 종료
kill -9 9650

2.3. 클러스터 생성

# Master 노드 등록
redis-cli --cluster create 127.0.0.1:7300 127.0.0.1:7302 127.0.0.1:7301
# Replica 노드 등록
redis-cli --cluster add-node 127.0.0.1:7400 127.0.0.1:7300 --cluster-slave
redis-cli --cluster add-node 127.0.0.1:7401 127.0.0.1:7301 --cluster-slave
redis-cli --cluster add-node 127.0.0.1:7402 127.0.0.1:7302 --cluster-slave

2.4. 테스트

  • 데이터 저장
$ redis-cli -c -p 7300 set a "first"
  • 메모리 사용률 확인
    • 명목메모리 사용률 : 버퍼/캐시 영역은 유휴 메모리로 간주 X
      • used / total = ( total - free ) / total
    • 실질메모리 사용률 : 버퍼/캐시 영역도 유휴 메모리로 간주
      • used2 / total = ( total - free2 ) / total = ( total - free - buffers - cached) / total
# 6개 노드 실행 후
$ free
              total        used        free      shared  buff/cache   available
Mem:        7923936     5212372     1827184        1452      884380     2456576
Swap:      20971512           0    20971512
# 6개 노드 종료 후
$ free
              total        used        free      shared  buff/cache   available
Mem:        7923936     5207696     1592812        1456     1123428     2454492
Swap:      20971512           0    20971512
# 명목사용률 : memused
$ sar -r 1
Linux 5.4.0-132-generic (worker3lab)    11/24/2022      _x86_64_        (4 CPU)

12:06:49 AM kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
12:06:50 AM   1804216   2449148   5132572     64.77     86584    736000   6394460     22.13   5391828    470308        48
# 명목사용률, 실질사용률 확인 스크립트
TOTAL=`free | grep ^Mem | awk '{print $2}'`
USED=`free | grep ^Mem | awk '{print $3}'`
NOTUSED=`free | grep ^Mem | awk '{print $6}'`
NOMINAL=`echo "100*$USED1/$TOTAL" | bc -l`
ACTUAL=`echo "100*($USED-$NOTUSED)/$TOTAL" | bc -l`
echo NOMINAL=${NOMINAL:0:5}% ACTUAL=${ACTUAL:0:5}%
---
# 6개 노드 실행 후
NOMINAL=65.77% ACTUAL=54.38%
# 6개 노드 종료 후
NOMINAL=65.77% ACTUAL=51.54%

3. 멀티 서버

다음과 같이 3개의 서버에 Cluster를 구성해 보겠다.

Redis Cluster 구성

3.1. 포트 포워딩

  • 서로 다른 네트워크 상의 서버들 간 Cluster 구축이기 때문에 포트포워딩 필수
    • 각 서버 별로 Redis server 와 Cluster bus 를 위한 port 2개 열어주어야 한다.
    • 여기서는 기존에 Port 번호에 10000을 더한 Port 번호를 Cluster bus 전용 Port로 지정하겠다.
  • 포트 포워딩한 Port 번호
    • Server1 : 7300, 7402, 17300, 17402
    • Server2 : 7301, 7400, 17301, 17400
    • Server3 : 7302, 7401, 17302, 17401

3.2. 기본 세팅

1) 폴더 생성 및 파일 복사

sudo mkdir /home/ubuntu/redis-cluster
sudo cp ~/redis-stable/redis.conf /home/ubuntu/redis-cluster/7300.conf
cd /home/ubuntu/redis-cluster
sudo mkdir etc

2) 파일 작성

# 필요 시 폴더 및 하위 파일들에 대한 사용 그룹 및 권한 변경
$ sudo chown -R ubuntu:ubuntu 7302
$ sudo chmod -R g+wx 7302

# Server1
vim /home/ubuntu/redis-cluster/7300.conf
vim /home/ubuntu/redis-cluster/7402.conf
# Server2
vim /home/ubuntu/redis-cluster/7301.conf
vim /home/ubuntu/redis-cluster/7400.conf
# Server3
vim /home/ubuntu/redis-cluster/7302.conf
vim /home/ubuntu/redis-cluster/7401.conf
  • Master Configuration
# Basic
daemonize yes
port 7300
pidfile redis_7300.pid
logfile "/home/ubuntu/redis-cluster/etc/redis_7300.log"
loglevel verbose
dir /home/ubuntu/redis-cluster/etc
bind 0.0.0.0 ::1
#bind 127.0.0.1 
#bind 192.168.0.101 (master)

# Limit
maxmemory 350mb
maxmemory-policy noeviction

# AOF
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir_7300"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# Cluster
cluster-config-file node-7300.conf
cluster-enabled yes
cluster-announce-ip 000.000.00.00
cluster-announce-port 7300
cluster-announce-bus-port 17300

# Password
requirepass thisispassword
masterauth thisispassword

# Lazyfree
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
replica-lazy-flush yes
lazyfree-lazy-user-del yes
  • Replication Configuration
# Basic
daemonize yes
port 7401
pidfile redis_7401.pid
logfile "/home/ubuntu/redis-cluster/etc/redis_7300.log"
dir /home/ubuntu/redis-cluster/etc
bind 192.168.0.101 127.0.0.1 ::1
#bind 127.0.0.1 
#bind 192.168.0.101 (master)

# Limit
maxmemory 350mb
maxmemory-policy noeviction

# AOF
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir_7400"
appendfsync everysec

# Cluster
cluster-config-file node-7300.conf
cluster-enabled yes
cluster-announce-ip 000.000.00.00
cluster-announce-port 7401
cluster-announce-bus-port 17401

# Password
requirepass thisispassword
masterauth thisispassword

# Replication
replica-serve-stale-data no
repl-ping-slave-period 10
repl-timeout 60

3.3. 노드 실행

# 모든 노드 실행
# server1 (master)
$ redis-server /home/ubuntu/redis-cluster/7300.conf
$ redis-server /home/ubuntu/redis-cluster/7402.conf

# server2 (worker3lab)
$ redis-server /home/ubuntu/redis-cluster/7301.conf
$ redis-server /home/ubuntu/redis-cluster/7400.conf

# server3 (worker4rasp)
$ redis-server /home/ubuntu/redis-cluster/7302.conf
$ redis-server /home/ubuntu/redis-cluster/7401.conf

# 실행 중인 redis 프로세스 확인
$ ps -ef | grep redis
ubuntu     86870       1  0 13:46 ?        00:00:00 redis-server 0.0.0.0:7300 [cluster]
ubuntu     86889       1  0 13:46 ?        00:00:00 redis-server 0.0.0.0:7402 [cluster]

# 노드 종료 (클러스터 등록할 때 노드 종료시키면 안된다.)
$ sudo kill -9 86870

3.4. 클러스터 생성

  • Master 노드 3개 등록
    • 6개의 IP:Port 를 모두 한 번에 입력하면 Master와 Replica가 알아서 짝지어진다.
    • 하지만, Failover를 제대로 수행하기 위해서는 서로 다른 서버의 Master와 Replica로 연결되어야 하기 때문에 직접 지정해주는 것이 좋다.
$ redis-cli -a [password] --cluster create [Server1 공인IP]:7300 [Server2 공인IP]:7301 [Server3 공인IP]:7302
  • Replica 노드 3개 등록
    • 특정 Master에 Replica를 지정해준다.
# replica 노드 추가
$ redis-cli -a [password] --cluster add-node [Server2 공인IP]:7400 [Server1 공인IP]:7300 --cluster-slave
$ redis-cli -a [password] --cluster add-node [Server3 공인IP]:7401 [Server2 공인IP]:7301 --cluster-slave
$ redis-cli -a [password] --cluster add-node [Server1 공인IP]:7402 [Server3 공인IP]:7302 --cluster-slave

3.5. Configuration 참고

  • bind 설정
    • 여기서 IP는 서버의 network interface IP이다.
    • 즉, 서버에서 리눅스 ifconfig 명령으로 나오는 IP 중 실제로 통신에 사용되는 IP로 클라이언트 IP를 의미하는 것이 아니다.
  • cluster-announce-ip 설정
    • 만일 Redis 노드가 서로 다른 네트워크 상에 있다면 각 서버의 공인 IP를 반드시 명시해줘야 한다.
    • 또한 한 서버에 여러 Redis 노드가 있는 경우 다른 네트워크에 있는 Redis 노드와 통신할 때 같은 공인IP로 인식하기 때문에 노드 설정 파일에 각각 cluster-announce-port 까지 명시해줘야 한다.
  • 아직 반영 안 한 설정
    • 아래 설정은 실제로 반영하지 않았지만, 추천하는 설정이다. 참고해두면 좋을 것 같다.
# Not Yet
timeout 2
no-appendfsync-on-rewrite no
latency-monitor-threshold 25
cluster-node-timeout 5000
cluster-slave-validity-factor 10
cluster-allow-reads-when-down yes

4. 시스템 튜닝

4.1. NUMA & Transparent Huge Page 설정 해제

  • Redis 서버는 메모리 영역에 대한 할당, 운영, 관리에 관련된 다양한 매커니즘을 자체적으로 제공
  • 리눅스 서버의 경우에도 자체적인 매커니즘(NUMA & THP) 제공
  • 리눅스 서버에서 제공하는 메모리 운영 매커니즘이 redis 서버에서 제공하는 매커니즘들이 정상적으로 작동되지 못하게 함
cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never

echo never > /sys/kernel/mm/transparent_hugepage/enabled

cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]

4.2. Client Keep Alive Time

  • 클라이언트가 redis 서버에 접속 후 일정 timeout 시간 초과 시 해당 세션은 종료되고 재접속 요구하는 경우 즉시 접속될 수 없는 상태일 때 대기 시간 발생
  • 클라이언트가 일정 시간 동안 작업을 수행하지 않아도 세션을 일정 시간 동안 유지시켜서 재접속 및 대기 시간 최소화
vim /etc/sysctl.conf
---
net.ipv4.tcp_keepalive_time = 7200
---wq!

4.3. 최적화 시스템 환경 설정

  • 메모리 overcommit은 물리 메모리 공간 이상을 쓸 수 있는 방법
    • 가상 메모리를 함께 사용하여 더 많은 메모리를 할당할 수 있는 기법
    • fork() 발생 가능성(RDB, AOF, replication 등)이 높은 redis 의 경우 설정 필요
vim /etc/sysctl.conf
---
vm.overcommit_memory=1
---wq!

4.4. 네트워크 설정

  • 많은 연결을 처리하기 위해 네트워크 설정
    • client 연결 요청은 accept() 호출 전에 queue 에 쌓임
    • queue 가 작으면 client 연결 요청이 drop 될 수 있으므로 다음 항목 크게 설정 필요
# 현재 네트워크 설정
sudo sysctl -w net.core.somaxconn=65535
cat /proc/sys/net/core/somaxconn
65535

# reboot 후에도 적용되도록 sysctl.conf 파일도 수정
vim /etc/sysctl.conf
---
net.core.somaxconn = 65535
---wq!

4.5. Max Number Of Open File

  • client 개수가 많아지거나 redis 서버 여러 개 띄우면 maximum open files 에러 메시지 뜸
    • maxclient 는 OS(Linux) 의 제한으로 설정 불가
    • 리눅스에서 파일이란 실제 파일 & 네트워크/소켓 접속 모두를 의미
    • max open files(nofile) 변경하면 위 에러 해결 가능
  • user 입력
    • redis 를 실행하는 user 가 redis 면 redis 를 입력
    • root 입력 시 root 에게 적용
    • * 입력 시 모든 user 에게 적용
vim /etc/security/limits.conf
---
redis soft nofile 65536
redis hard nofile 65536
---wq!

4.6. Max Number Of Processes

  • redis 서버는 여러 개의 프로세스를 사용하지 않으므로 아래 수정을 굳이 할 필요는 없지만 추후 발생 가능 문제 대비를 위해 설정
  • redis 서버는 평상시에 1개 프로세스로 운영
    • 자식 프로세스가 필요할 때 부모 프로세스 포함 최대 2개 프로세스 동시에 뜸
    • 아래에서 언급하는 프로세스는 thread 포함해서 계산
    • redis 서버는 메인 thread 포함해서 4개의 thread 로 운영
  • redis 프로세스
    • main thread : redis 서버에 수행되는 대부분의 명령어와 이벤트 처리 역할
    • sub thread 1(BIO-Close-File) :
      • AOF 에 데이터 rewrite 할 때 기존 파일 close 하고, 새로운 AOF 파일에 write 할 때 사용
    • sub thread 2(BIO-AOF-Resync)
      • AOF 에 쓰기 작업 수행할 때 사용
    • sub thread 3(BIO-Lazy-Free)
      • UNLINK, FLUSHALL, FLUSHDB 명령어 실행할 때 빠른 성능 보장을 위해 백그라운드에서 사용
vim /etc/security/limits.conf
---
redis soft nproc 131072
redis hard nproc 131072
---wq!

5. 그 외 명령어

5.1. 수동 설정

  • Cluster 명령어를 이용한 수동 Cluster 구축
# cluster 멤버 등록
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster meet 127.0.0.1 6301
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster meet 127.0.0.1 6302
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster meet 127.0.0.1 6400
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster meet 127.0.0.1 6401
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster meet 127.0.0.1 6402

# cluster 에 등록된 멤버 확인
redis-cli -a [xpxmfltm1019] -h 127.0.0.1 -p 6300 cluster nodes

<id> <ip:port@cport> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slog> <slot> ... <slot>
989ca17023198c4b68bfbb0c9fe04fcd0e0fab05 127.0.0.1:6302@16302 master - 0 1668324073000 3 connected 10923-16383
1e589bcda3d1c7f03d044773770efa56c7185375 127.0.0.1:6402@16402 master - 0 1668324073833 0 connected
8b60603728c031972f85c3eb8d65ff9675ab12cc 118.37.137.82:6301@16301 master - 1668324036123 1668324035618 2 disconnected 5461-10922
ed2f762504ddcb15141694b128dd2719ee8902f3 118.37.137.82:6300@16300 myself,master - 0 1668324058000 1 connected 0-5460
295649ba055534f8cc18745fad4f34ae5af226a1 127.0.0.1:6401@16401 master - 0 1668324072312 0 connected
3b876888de4aa172ffc7185cb1d2e84cad4f68f7 127.0.0.1:6400@16400 master - 0 1668324073000 0 connected

# 6400번 노드를 6300 번 노드의 복제 서버로 설정
redis-cli -a [thisispassword] -h 127.0.0.1 -p 6400 cluster replicate ed2f762504ddcb15141694b128dd2719ee8902f3 
redis-cli -a [thisispassword] -h 127.0.0.1 -p 6401 cluster replicate 8b60603728c031972f85c3eb8d65ff9675ab12cc 
redis-cli -a [thisispassword] -h 127.0.0.1 -p 6402 cluster replicate 989ca17023198c4b68bfbb0c9fe04fcd0e0fab05 

# Master 노드에 슬롯 설정 (기본적으로 16,384 개의 슬롯 가짐)
redis-cli -h 127.0.0.1 -p 6300 cluster addslots {0..5461}
redis-cli -h 127.0.0.1 -p 6301 cluster addslots {5462..10922}
redis-cli -h 127.0.0.1 -p 6302 cluster addslots {10923..16383}

# 설정된 슬롯 확인
redis-cli -h 127.0.0.1 -p 6400 cluster slots

# cluster 설정 상태 확인
redis-cli -c -h 127.0.0.1 -p 6300 cluster info

# cluster 초기화
redis-cli -a [xpxmfltm1019] --cluster call 127.0.0.1:6300 flushall
redis-cli -a [xpxmfltm1019] --cluster call 127.0.0.1:6300 cluster reset

[Redis 에 대해 더 궁금하다면?]

REFERENCES