관련글
2023.04.17 - [DB] - 1. Redis란? Docker 설치와 함께 알아보기
Redis 마스터 / 슬레이브의 필요성
전 블로그에서는 Redis Standalone(Single Node)구성을 살펴봤습니다. 단일노드로 구성된 레디스는 장애 발생시 서비스가 중단되는 단점이 있습니다. 이를 해결하기 위해 마스터 / 슬레이브구성이 필요합니다.
마스터 / 슬레이브 장점
1. 고가용성(Failover)
마스터 노드가 장애로 중단되는 경우에도 계속해서 서비스를 제공할 수 있다.(무중단서비스)
2. 확장성
다중 슬레이브 노드에 데이터를 분산하고, 읽기 작업에 대한 처리를 위임함으로써 빠른 응답속도를 확보할 수 있다.
3. 데이터 복제 및 복구
실시간으로 데이터가 각 슬레이브 노드에 복제되므로 마스터 노드의 데이터 손실에 대응할 수 있다.
고려사항
- 다중 노드 특성상 충분한 네트워크 대역폭이 확보되어야 합니다. 단일 서버 구성이 아닌 경우, 각 서버의 하드웨어 성능등을 충분히 고려해야 합니다.
- 각 노드를 효과적으로 모니터링 할 수 있는 방법을 모색해야 합니다.
- 자동장애복구, 수동장애복구 기능의 마스터 승격 기능에 대한 기능검토와 테스트가 충분히 이루어져야 합니다.
Redis Sentinel
마스터/슬레이브 구성에서 고가용성을 위해 Redis Sentinel을 사용합니다.
( 클러스터와 Sentinel은 Failover를 관리하는 구성체계가 다르므로 같이 사용될 수 없음 )
마스터 노드 장애시, 자동으로 복구(Automastic failover)하는 기능을 Sentinel이 제공합니다.
Sentinel 주요특징
1. 모니터링(Monitoring)
마스터, 슬레이브 노드의 상태를 감시합니다.
2. 알림(Notification)
노드의 상태를 특정 시스템, 프로그램 혹은 API로 전달할 수 있습니다.
3. Automatic failover(자동 복구)
마스터 노드 장애 시 Sentinel은 이를 감지하고, 일련의 승격 프로세스를 통해 특정 슬레이브 노드를 마스터 노드로 승격합니다.
4. Configuration Provider
클라이언트는 Sentinel을 통해 Failover상황에도 동일한 엔드포인트로 Redis를 사용할 수 있습니다.
docker-compose-sentinel.yaml
version: '3'
x-redis-base: &redis-base
image: bitnami/redis:6.2.10
networks:
- redis-net
x-redis-sentinel-base: &redis-sentinel
image: bitnami/redis-sentinel:6.2.10
environment:
- REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
- REDIS_MASTER_HOST=redis
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_SET=mymaster
- REDIS_SENTINEL_QUORUM=2
networks:
- redis-net
services:
redis:
<<: *redis-base
environment:
- REDIS_REPLICATION_MODE=master
- ALLOW_EMPTY_PASSWORD=yes
ports:
- '6379:6379'
redis-slave1:
<<: *redis-base
environment: &slave_env
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis
- ALLOW_EMPTY_PASSWORD=yes
ports:
- '6379'
redis-slave2:
<<: *redis-base
environment: *slave_env
ports:
- '6379'
# For Sentinel
redis-sentinel1:
<<: *redis-sentinel
ports:
- "26379:26379"
depends_on:
- redis
- redis-slave1
- redis-slave2
redis-sentinel2:
<<: *redis-sentinel
ports:
- "26380:26379"
depends_on:
- redis-sentinel1
redis-sentinel3:
<<: *redis-sentinel
ports:
- "26381:26379"
depends_on:
- redis-sentinel2
networks:
redis-net:
driver: bridge
ALLOW_EMPTY_PASSWORD=yes
옵션으로 패스워드 사용을 해제할 수 있음- 위에서 사용한 bitnami이미지는 사용 편의성, 호환성, 보안성, 확장성 및 커뮤니티 지원과 같은 다양한 장점을 제공함
- 3개(홀수)의 Sentinel을 구성한 이유는 Failover시 마스터 승격 투표의 과반수 이상 결정을 위함
--scale
옵션으로 sentinel을 원하는 수 만큼 실행할 수 있으나 포트 매핑과정에서 충돌이 나는 버그 존재함 (compose 버전 문제로 확인 됨)
compose 실행
$ docker-compose -f docker-compose-sentinel.yaml up
정상 실행 출력 로그
redis-sentinel3_1 | 1:X 16 Jun 2023 07:50:04.128 * +sentinel sentinel 5e1324a023d38ac018c4048e1279cfd2c802da4c 192.168.176.5 26379 @ mymaster 192.168.176.4 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:50:04.874 * +sentinel sentinel 406025aa9e4615b5fca802041deeac9c9939fc0e 192.168.176.7 26379 @ mymaster 192.168.176.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:50:04.874 * +sentinel sentinel 406025aa9e4615b5fca802041deeac9c9939fc0e 192.168.176.7 26379 @ mymaster 192.168.176.4 6379
Sentinel 접속 및 마스터/슬레이브 정보 확인
$ redis-cli -p 26379
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.160.2:6379,slaves=2,sentinels=3
- Master정보와 Slave, Sentinel의 활성화 갯수를 확인
127.0.0.1:26379> sentinel masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "192.168.160.2"
5) "port"
6) "6379"
7) "runid"
8) "0aa1c22564e1fe33018f6fc2eb7df137710e8ba8"
...생략...
- default 마스터노드명은
mymaster
로 설정 됨 - compose environment에
REDIS_MASTER_SET
옵션으로 노드명 설정 가능
master 확인
127.0.0.1:26379> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "172.26.0.4"
5) "port"
6) "6379"
...중략...
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "2"
- 마스터노드의 ip / port 및 슬레이브 정보등을 확인
Failover Test
Failover 테스트를 하기 위해 간단한 파이썬 프로그램을 실행합니다.
테스트용 프로그램은 1초마다 Sentinel을 통해 얻은 마스터 노드 정보를 출력합니다.
docker-compose-sentinel.yaml 파일에 다음을 추가 합니다.
python-app:
build:
context: .
dockerfile: Dockerfile
networks:
- redis-net
depends_on:
- redis-sentinel3
Dockerfile
도커파일을 도커를 실행하는 위치에 생성합니다.
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD [ "python", "-u", "client4sentinel.py" ]
-u
옵션을 주어야만 파이썬에서 출력하는 Print로그를 실시간으로 확인할 수 있습니다.
client4sentinel.py
import time
from datetime import datetime
from redis import Sentinel
from redis.sentinel import MasterNotFoundError
s = Sentinel([('redis-sentinel1', 26379)], socket_timeout=1)
master = s.master_for('mymaster', socket_timeout=1)
while True:
try:
ip, port = s.discover_master('mymaster')
print(datetime.now(), ', Current master info:', ip, port)
except MasterNotFoundError as e:
print(datetime.now(), ', Not Found master!!')
finally:
time.sleep(1)
redis-sentinel1
은 컴포즈에 기술한 센티넬 서비스명입니다.
Compose 재실행
docker-compose -f docker-compose-sentinel.yaml down
docker-compose -f docker-compose-sentinel.yaml up --build
로그
python-app_1 | 2023-06-16 07:51:56.638240 , Current master info: 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:51:57.398 * +sentinel sentinel b5627dded55437d05a5486db1cbc636e25e699c1 192.168.208.7 26379 @ mymaster 192.168.208.4 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:51:57.398 * +sentinel sentinel b5627dded55437d05a5486db1cbc636e25e699c1 192.168.208.7 26379 @ mymaster 192.168.208.4 6379
python-app_1 | 2023-06-16 07:51:57.641038 , Current master info: 192.168.208.4 6379
python-app_1 | 2023-06-16 07:51:58.642896 , Current master info: 192.168.208.4 6379
python-app_1 | 2023-06-16 07:51:59.645808 , Current master info: 192.168.208.4 6379
python-app_1 | 2023-06-16 07:52:00.647456 , Current master info: 192.168.208.4 6379
매초마다 마스터 정보를 출력합니다. 이제 master node에 redis-cli로 접근해서 잠시 블로킹 상태로 만들겠습니다.
redis-cli DEBUG sleep 30
Failover 수행 로그
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:20.110 # +sdown master mymaster 192.168.208.4 6379
python-app_1 | 2023-06-16 07:57:20.313846 , Current master info: 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:20.983 # +sdown master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.046 # +odown master mymaster 192.168.208.4 6379 #quorum 2/2
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.046 # +new-epoch 1
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.046 # +try-failover master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.063 # +vote-for-leader 02252d44eb04103d53788ab64014a04a6a66a7ee 1
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:21.081 # +new-epoch 1
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:21.081 # +new-epoch 1
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:21.098 # +vote-for-leader 02252d44eb04103d53788ab64014a04a6a66a7ee 1
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.098 # b5627dded55437d05a5486db1cbc636e25e699c1 voted for 02252d44eb04103d53788ab64014a04a6a66a7ee 1
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.098 # 94bc4b0f836a77c23a52d0929bcd350600177cd7 voted for 02252d44eb04103d53788ab64014a04a6a66a7ee 1
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:21.098 # +vote-for-leader 02252d44eb04103d53788ab64014a04a6a66a7ee 1
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:21.098 # +sdown master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.126 # +elected-leader master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.126 # +failover-state-select-slave master mymaster 192.168.208.4 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:21.164 # +odown master mymaster 192.168.208.4 6379 #quorum 3/2
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:21.164 # Next failover delay: I will not start a failover before Fri Jun 16 08:03:21 2023
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.179 # +selected-slave slave 192.168.208.2:6379 192.168.208.2 6379 @ mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.179 * +failover-state-send-slaveof-noone slave 192.168.208.2:6379 192.168.208.2 6379 @ mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:21.242 * +failover-state-wait-promotion slave 192.168.208.2:6379 192.168.208.2 6379 @ mymaster 192.168.208.4 6379
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.242 # Connection with master lost.
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.242 * Caching the disconnected master state.
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.242 * Discarding previously cached master state.
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.242 # Setting secondary replication ID to b64d226b674f04565dc73d303c6a7b8c0512c393, valid up to offset: 67306. New replication ID is 0e9f083abd841a3e2ff0bf8043e153ad9e85688c
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.242 * MASTER MODE enabled (user request from 'id=6 addr=192.168.208.6:54903 laddr=192.168.208.2:6379 fd=11 name=sentinel-02252d44-cmd age=328 idle=0 flags=x db=0 sub=0 psub=0 multi=4 qbuf=188 qbuf-free=40766 argv-mem=4 o
bl=45 oll=0 omem=0 tot-mem=61468 events=r cmd=exec user=default redir=-1')
redis-slave2_1 | 1:M 16 Jun 2023 07:57:21.251 # CONFIG REWRITE executed with success.
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:21.260 # +odown master mymaster 192.168.208.4 6379 #quorum 3/2
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:21.260 # Next failover delay: I will not start a failover before Fri Jun 16 08:03:21 2023
python-app_1 | 2023-06-16 07:57:21.315819 , Not Found master!!
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:22.165 # +promoted-slave slave 192.168.208.2:6379 192.168.208.2 6379 @ mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:22.165 # +failover-state-reconf-slaves master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:22.204 * +slave-reconf-sent slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.4 6379
redis-slave1_1 | 1:M 16 Jun 2023 07:57:22.204 # Connection with master lost.
redis-slave1_1 | 1:M 16 Jun 2023 07:57:22.205 * Caching the disconnected master state.
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.205 * Connecting to MASTER 192.168.208.2:6379
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.205 * MASTER <-> REPLICA sync started
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.205 * REPLICAOF 192.168.208.2:6379 enabled (user request from 'id=6 addr=192.168.208.6:51869 laddr=192.168.208.3:6379 fd=11 name=sentinel-02252d44-cmd age=328 idle=0 flags=x db=0 sub=0 psub=0 multi=4 qbuf=342 qbuf-free=4
0612 argv-mem=4 obl=45 oll=0 omem=0 tot-mem=61468 events=r cmd=exec user=default redir=-1')
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:22.205 # +config-update-from sentinel 02252d44eb04103d53788ab64014a04a6a66a7ee 192.168.208.6 26379 @ mymaster 192.168.208.4 6379
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:22.205 # +switch-master mymaster 192.168.208.4 6379 192.168.208.2 6379
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:22.205 * +slave slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.2 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:22.205 # +config-update-from sentinel 02252d44eb04103d53788ab64014a04a6a66a7ee 192.168.208.6 26379 @ mymaster 192.168.208.4 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:22.205 # +switch-master mymaster 192.168.208.4 6379 192.168.208.2 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:22.205 * +slave slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.2 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:22.205 * +slave slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:22.205 * +slave slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 # CONFIG REWRITE executed with success.
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 * Non blocking connect for SYNC fired the event.
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 * Master replied to PING, replication can continue...
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 * Trying a partial resynchronization (request b64d226b674f04565dc73d303c6a7b8c0512c393:67306).
redis-slave2_1 | 1:M 16 Jun 2023 07:57:22.222 * Replica 192.168.208.3:6379 asks for synchronization
redis-slave2_1 | 1:M 16 Jun 2023 07:57:22.222 * Partial resynchronization request from 192.168.208.3:6379 accepted. Sending 446 bytes of backlog starting from offset 67306.
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 * Successful partial resynchronization with master.
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 # Master replication ID changed to 0e9f083abd841a3e2ff0bf8043e153ad9e85688c
redis-slave1_1 | 1:S 16 Jun 2023 07:57:22.222 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
python-app_1 | 2023-06-16 07:57:22.318237 , Current master info: 192.168.208.2 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.162 * +slave-reconf-inprog slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.162 * +slave-reconf-done slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.262 # -odown master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.262 # +failover-end master mymaster 192.168.208.4 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.263 # +switch-master mymaster 192.168.208.4 6379 192.168.208.2 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.263 * +slave slave 192.168.208.3:6379 192.168.208.3 6379 @ mymaster 192.168.208.2 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:23.263 * +slave slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
python-app_1 | 2023-06-16 07:57:23.319664 , Current master info: 192.168.208.2 6379
python-app_1 | 2023-06-16 07:57:24.321228 , Current master info: 192.168.208.2 6379
redis-sentinel3_1 | 1:X 16 Jun 2023 07:57:25.211 # +sdown slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
redis-sentinel1_1 | 1:X 16 Jun 2023 07:57:25.249 # +sdown slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
python-app_1 | 2023-06-16 07:57:25.323027 , Current master info: 192.168.208.2 6379
redis-sentinel2_1 | 1:X 16 Jun 2023 07:57:26.280 # +sdown slave 192.168.208.4:6379 192.168.208.4 6379 @ mymaster 192.168.208.2 6379
python-app_1 | 2023-06-16 07:57:26.324887 , Current master info: 192.168.208.2 6379
python-app_1 | 2023-06-16 07:57:27.326593 , Current master info: 192.168.208.2 6379
- 각 Sentinel은 마스터의 서비스가 동작하지 않는것을 감지, failover를 수행합니다.
- 각 Sentinel은 투표를 통해 어떤 슬레이브가 마스터로 승격할지를 결정합니다. (과반수 투표)
- 새로운 마스터 노드 선출까지 약 2초 이내에 처리되었으며, 그 동안 python-app에서 마스터노드 접근에 오류가 발생함을 확인할 수 있습니다.
마치며..
고가용 레디스 서비스를 위한 마스터/슬레이브 구성을 도커컴포즈를 사용하여 간단하게 구성해봤습니다.
여러개의 노드를 사용하는 마스터/슬레이브, 클러스터링 구성은 각 노드 상태를 모니터링하고 제어할 수 있어야 합니다. 다음장에서는 레디스 클러스터링 환경을 도커컴포즈를 사용해서 구축해보고, 모니터링 프레임워크를 사용해서 노드를 모니터링, 제어하는 기능을 소개합니다.
Reference
Docker-Hub Bitnami Redis (https://hub.docker.com/r/bitnami/redis-sentinel)
tags
레디스 redis master slave 도커 컴포즈 센티넬 구성 python 파이썬 장단점 마스터/슬레이브
'DataBase' 카테고리의 다른 글
[Oracle] 오라클 단일, 다중 With절 사용방법과 유스케이스 (0) | 2023.07.07 |
---|---|
1. Redis란? Docker 설치 및 cli 명령어 알아보기 (0) | 2023.04.17 |
PostgreSQL 날짜 API 다루기( 두 날짜 사이 시간 계산, extract, age 등 ) (0) | 2023.02.09 |
PostgreSQL 캐스팅 사용 방법 유용한 예제(숫자, 문자, 날짜 변환) (0) | 2023.02.07 |
PostgreSQL 테이블 CRUD 쿼리 예제 (1) | 2023.02.06 |