4. Redis 복제
Redis 복제
Redis 주요 특징 중 하나가 DBMS에서 제공하는 유사한 복제 기능이 있다는 것입니다.
복제 기능은 장애 발생 시 빠른 서버 교체나 장비 교체 등에 사용할 수 있습니다.
Redis 복제 모델
Redis는 마스터/슬레이브 형태의 복제 모델을 제공합니다.
이를 통해서 마스터의 변경이 슬레이브로 전파됩니다.
한 대의 슬레이브는 오직 한 대에 마스터만 가질 수 있고 슬레이브는 다른 장비의 마스터로도 동작할 수 있습니다.
Docker Compose를 이용한 Redis 마스터 슬레이브 구성하기
1. 네트워크 생성
$ docker network create redis-network --driver bridge
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
62cbf5d8ac2c redis-network bridge local
2. docker-compose.yml 작성
이미지는 bitnami/redis-sentinel를 사용하였습니다.
$ sudo vim docker-compose.yml
version: '2'
networks:
redis-network:
driver: bridge
external: true
services:
redis-master:
image: 'bitnami/redis:latest'
container_name: 'redis-master'
environment:
- REDIS_REPLICATION_MODE=master
- ALLOW_EMPTY_PASSWORD=yes
networks:
- redis-network
ports:
- 6379:6379
redis-slave-1:
image: 'bitnami/redis:latest'
container_name: 'redis-slave-1'
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 6480:6379
depends_on:
- redis-master
networks:
- redis-network
redis-slave-2:
image: 'bitnami/redis:latest'
container_name: 'redis-slave-2'
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- ALLOW_EMPTY_PASSWORD=yes
ports:
- 6481:6379
depends_on:
- redis-master
networks:
- redis-network
3. contanier 생성
$ docker-compose up -d
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
65a4f140a9eb bitnami/redis:latest "/opt/bitnami/script…" About a minute ago Up About a minute 0.0.0.0:6481->6379/tcp redis-slave-2
a44bde266d56 bitnami/redis:latest "/opt/bitnami/script…" About a minute ago Up About a minute 0.0.0.0:6480->6379/tcp redis-slave-1
53bd2ba6960f bitnami/redis:latest "/opt/bitnami/script…" About a minute ago Up About a minute 0.0.0.0:6379->6379/tcp redis-master
4. 확인
$ docker exec -i -t redis-master redis-cli
127.0.0.1:6379> info
...
# Replication
role:master
connected_slaves:2
slave0:ip=172.21.0.3,port=6379,state=online,offset=1890,lag=0
slave1:ip=172.21.0.4,port=6379,state=online,offset=1890,lag=0
...
info 명령어를 사용하면 connected_slaves가 2대 인 것을 확인할 수 있습니다.
이번엔 마스터에서 데이터를 저장해 슬레이브에서 확인해 보도록 하겠습니다.
127.0.0.1:6379> set name bk
OK
127.0.0.1:6379> get name
"bk"
127.0.0.1:6379> exit
$ docker exec -i -t redis-slave-1 redis-cli
127.0.0.1:6379> get name
"bk"
슬레이브에 접속해 같은 Key 값으로 조회 시 마스터에서 저장한 Value값이 출력되는 것을 확인할 수 있습니다.
Redis 복제 과정
Redis의 복제 과정을 간략하게 정리하면 다음과 같습니다.
1. 마스터 서버가 설정되면, replicationCron에서 현재 상태에 따라 connectWithMaster를 호출한다.
2. 마스터는 복제를 위해 RDB를 생성한 후 슬레이브에 전송한다.
3. 슬레이브는 RDB를 로드하고, 나머지 차이에 대한 명령을 마스터에 전달받아 복제를 완료한다.
Redis 복제 사용 시 주의사항
1. slaveof no one을 기억하자
복제를 사용할 때 흔희 하는 실수 중 하나가 Redis의 복제 과정상 특징을 모른 채 DBMS와 동일하다고 생각하기 때문에 발생합니다.
슬레이브는 마스터의 상태를 지속적으로 감시하면서 바뀌는 내용을 계속 전달받습니다.
만약 이상이 발생해서 마스터와 연결이 끊어지면 재접속을 시도하며 마스터에 전체 데이터를 다시 가져와 마스터의 최종 상태로 슬레이브의 상태가 변경됩니다.
문제는 가장 마지막에 emptyDb를 호출하기 때문에 발생합니다.
마스터와 동일한 데이터를 유지하기 위해서 RDB를 읽어 들이기 전에 현재 슬레이브의 데이터를 모두 삭제하고 마스터와 싱크를 맞추므로 마스터에 데이터가 없을 경우 모든 데이터가 날아갑니다. 이 경우, 장애 발생 시 슬레이브를 사용할 수 없게 됩니다.
그래서 slaveof no one이라는 명령어가 중요한데, 일단 장애 판단 여부는 관리자나 다른 서비스에서 체크할 수 있다고 하고 명시적으로 현재 마스터에 장애가 일어난 것을 알고 있다면 해당 슬레이브에 slaveof no one 명령어를 줘서 더 이상 슬레이브로 동작하지 않도록 하여 데이터 유실을 막아야 합니다.
2. 복제 시에 무조건 RDB를 백그라운드로 생성한다는 것을 주의하자.
일반적으로 RDB를 사용하면 메모리를 두 배로 사용할 가능성이 있기 때문에 사용하지 않는 경우도 있습니다.
반면 복제를 사용하게 되면 무조건 슬레이브에 전달할 RDB를 만들기 위해 fork 해서 RDB를 생성합니다.
이때 새로운 문제가 발생할 여지가 있습니다. 따라서 하나의 프로세스가 너무 많은 메모리를 사용하지 않도록 나누는 과정이 필요합니다.
Redis 복제를 이용한 실시간 마이그레이션
Redis의 복제 기능을 사용해 가능한 한 다운타임 없이 쉽게 데이터를 이전할 수 있습니다.
1. 새로운 Redis 서버 생성
데이터를 이전할 새로운 Redis 서버를 생성합니다.
2. 새로운 Redis 서버를 기존 마스터의 슬레이브로 설정
127.0.0.1:6380> slaveof {기존 마스터 서버 IP} {기존 마스터 서버 Port}
3. 새로운 Redis 서버에 slave-read-only 설정 off
기본적으로 슬레이브는 slave-read-only로 설정되는데, 이 기능을 꺼서 슬레이브에서도 업데이트가 가능하도록 설정해야 합니다.
127.0.0.1:6380> config set slave-read-only no
4. 클라이언트 마스터 설정 변경
클라이언트들이 새로운 Redis 서버를 마스터로 인식하도록 설정을 바꿉니다.
이때 기존 마스터와 새로운 Redis 서버로 모든 데이터가 전달되고, 마스터에 전달된 내용은 자동적으로 새로운 서버로 복제되어 저장됩니다.
따라서 새로운 Redis 서버에는 모든 데이터가 남아 있게 됩니다.
5. 기존 마스터와 연결 종료
slaveof no one 명령어를 이용해서 새로운 Redis 서버와 기존 마스터와의 연결을 종료합니다.
이 작업을 하기 전에 기존 마스터 장비에 더는 요청이 없는다 것을 확인해야 합니다.
127.0.0.1:6380> slaveof no one
6. 기존 마스터 제거
모든 데이터가 이전되었으면 기존 마스터를 제거합니다.