Skip to content

Instantly share code, notes, and snippets.

@Maisy
Created November 9, 2021 13:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Maisy/460d228dd2e9915991de539335e3c00a to your computer and use it in GitHub Desktop.
Save Maisy/460d228dd2e9915991de539335e3c00a to your computer and use it in GitHub Desktop.

Redis Sentinel

Redis

  • Master는 여러 개의 복제 노드를 가질 수 있다. (1차 복제 서버)
    • 복제 노드가 또 복제 노드를 가질 수 있음.(하지만 얘는 master 후보 아님)

Redis Failover

  • 1차 복제 서버 중 conf파일에 있는 replica-priority값이 가장 작은 값을 가진 서버가 마스터에 선정됨
  • 0으로 설정할 경우 master로 승격되지 않음
  • 같은 값을 가지는 경우에 대해서는 다수결

master와 1차 복제서버가 거의 동시에 다운되었을때

  • master 다운시 2차복제서버는 Failover 대상이 아님

  • 만약 master와 1차복제서버가 동시에 다운되는 경우 sentinel에서는 2차복제서버를 알지 못해 master로 승급 할 수 없다.

  • 만약 master와 1차복제서버간에 다운타임의 충분한 차이가 있으면 sentinel에서는 1차복제서버를 마스터로 승격하면서 2차복제서버의 정보를 얻어올 수 있고, 1차복제서버가 다운되면 2차복제서버를 마스터로 승급시킬 수 있다. (https://mozi.tistory.com/378)

Redis Sentinel

Redis Mater-Slave 이중화 구성 관리툴로 Redis instance와 별도 설치 및 구성 필요 Master 장애시 장애 확정 및 새로운 Master 선출 투표를 위해 과반수가 가능해야함 (최소 3개 이상 필요) 전체 최소 이중화 구성 instance 개수는 5개 (Sentinel : 5개, Redis Master : 1개, Redis Slave : 1 개)

Redis Cluster

별도의 툴 설치 없이 Redis Server Cluser Mode 설정을 켜서 바로 사용 가능 멀티 마스터 구성으로 데이터를 분산 저장하며 고가용성 보장을 위해 각 Master instance는 최소 1개 이상의 Slave instance가 존재해야 함 이론상 최소 1개 instance로 Cluster 구성이 가능하나 실사용을 위한 최소 구성은 Master : 3, Slave : 3이 적정함


Redis Sentinel

  • Sentinel로 구성하는 Redis HA는 1 Master, N Replicas, M Sentinel
  • M은 3개이상의 홀수개가 이상적이며, 최소 1 Master, 1 Replica, 3 Sentinel이 권장된다.

하는일

  1. Montoring: redis master, replica 모니터링
  2. Automatic Failover
  • Master Redis의 상태를 감시. Master가 down되면 slave 중 어떤 redis서버를 master로 승격시킬지 투표 -> sentinel의 투표를 가장 많이 받은 redis server가 master로 승격됨 -> 이후 장애를 해결한 원래 master는 재시작시 slave로 시작됨

  • redis sentinel의 노드 개수는 항상 홀수로 설정(다수결원칙)

  1. Notification: redis instance들이 failover되었을 때 pub/sub으로 application(client)에게 알리거나 shell script로 관리자에게 email, sms로 알림가능

slave가 master로 승격될때

sentinel은

  1. redis.conf 파일을 조작하여 slave를 master로 변경
  2. 자기자신의 sentinel.conf정보를 조작하여 감시하는 redis 서버 정보를 update
  3. (down되었던 master정보는 메모리에 저장)

down되었던 master가 다시 시작되었을 때

sentinel은 해당 master의 redis.conf를 조작하여 현재 master의 slave로 설정

  • 일시적으로 master가 2대가 됨. 만약 down되었다가 restart된 redis에 data가 저장되는 경우, slave로 전환되면서 master rdb파일을 바탕으로 data sync를 하기때문에 데이터 유실 가능성있음. (따라서 restart 된 master에는 접근 못하도록 막아야함)

Redis Sentinel Docker compose file

version: '3.7'
services:
  redis-master:
    # image: bitnami/redis:5.0
    image: bitnami/redis:6.2.4
    container_name: redis-master
    hostname: redis-master
    environment:
      - REDIS_REPLICATION_MODE=master
      - REDIS_PASSWORD=brightics
    volumes:
      - redis-data1:/bitnami/redis/data
    ports:
      - 6379:6379
  redis-replica:
    image: bitnami/redis:6.2.4
    container_name: redis-replica
    hostname: redis-replica
    environment:
      - REDIS_REPLICATION_MODE=replica
      - REDIS_PASSWORD=brightics
      - REDIS_MASTER_HOST=redis-master
      - REDIS_MASTER_PASSWORD=brightics
    volumes:
      - redis-data2:/bitnami/redis/data
  redis-sentinel:
    image: bitnami/redis-sentinel:5.0
    hostname: sentinel
    environment:
      - REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS=3000
      - REDIS_PASSWORD=brightics
      - REDIS_MASTER_HOST=redis-master
      - REDIS_MASTER_PASSWORD=brightics
      - REDIS_MASTER_PORT_NUMBER=6379
      - REDIS_MASTER_SET=redis-master
      - REDIS_SENTINEL_QUORUM=2
    depends_on:
      - redis-master
      - redis-replica
volumes:
  redis-data1:
    driver: local
  redis-data2:
    driver: local

sentinel environment

REDIS_SENTINEL_QUORUM=2

  • master가 죽었다고 판단하는 최소 sentinel process의 개수.
  • failover 시 Master가 죽었다는 걸 판단하기 위해서는 다수결의 원칙이 적용 (홀수로 설정해야함) -> sentinel process가 총 3개일 경우 2로 설정 -> sentinel process가 총 5개일 경우 3으로 설정

REDIS_SENTINEL_FAILOVER_TIMEOUT (Default: 180000ms)

failover시 아래와 같은 로그를 확인할 수 있다.

redis-sentinel_3  | 1:X 09 Nov 2021 11:59:57.146 # Next failover delay: I will not start a failover before Tue Nov  9 12:05:57 2021
  • 장애조치가 일정 시간이 지나도 완료되지 않았을 때 취소(abort)하는 시간
  • 주의할 것은 장애조치 시작부터 완료될때까지의 시간이 아니고, 각 단계마다의 시간을 체크한다. 1~6 각 단계 완료 직후에 failover_state_change_time을 세팅하고, 이 시각과 현재 시각을 비교해서 failover-timeout 보다 크면 장애조치를 취소한다.
  • 장애조치를 취소(abort)한다는 것은 각 단계마다 설정한 플레그를 초기화하고 선정된 복제 정보를 삭제한다. 객관적 다운(odown) 플레그는 그대로 둔다. 정확한 의미에서 모두 롤백(rollback)하는 것은 아니지만 장애조치를 다시 시작할 수 있도록 초기화하는 것이다. 따라서 취소된 후 센티널 서버는 odown 단계에서 부터 다시 시작할 수 있다.

REDIS_SENTINEL_DOWN_AFTER_MILLISECONDS (default: 60000ms)

  • 이 시간 동안 해당 서버(마스터, 복제, 센티널)와 통신이 안되면 주관적 다운(sdown) 상태로 변경한다.

Sentinel process 3개 실행

$ docker-compose up --scale redis-sentinel=3 -d
Creating redis-replica ... done
Creating redis-master  ... done
Creating redis-sentinel_redis-sentinel_1 ... done
Creating redis-sentinel_redis-sentinel_2 ... done
Creating redis-sentinel_redis-sentinel_3 ... done

logging

$ docker-compose logs -f

sentinel 접속

  • default connection TCP port는 26379
$ docker exec -it redis-sentinel_redis-sentinel_3 bash # sentinel container로 붙기
@sentinel:/$ redis-cli -p 26379 -a brightics
  • sentinel info 확인
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=redis-master,status=ok,address=172.18.0.3:6379,slaves=1,sentinels=3
  • Master 정보 확인
127.0.0.1:26379> sentinel master redis-master
 1) "name"
 2) "redis-master"
 3) "ip"
 4) "172.18.0.3"
 5) "port"
 6) "6379"
 7) "runid"
 8) "180a0685825d51f6f0258e99f0855654ee9563f5"
 (...)

redis session 접속

$ docker exec -it redis-master bash # redis container로 붙기

@redis-replica:/$ redis-cli
127.0.0.1:6379> auth brightics
OK
127.0.0.1:6379> set samplekey samplevalue
OK
127.0.0.1:6379> get samplekey

master 강제 종료

$ docker stop redis-master
redis-master exited with code 0
redis-replica     | 1:S 09 Nov 2021 09:54:45.304 * Connecting to MASTER redis-master:6379
redis-sentinel_1  | 1:X 09 Nov 2021 09:54:47.946 # +sdown master redis-master 172.18.0.3 6379
redis-sentinel_3  | 1:X 09 Nov 2021 09:54:47.963 # +sdown master redis-master 172.18.0.3 6379
redis-sentinel_2  | 1:X 09 Nov 2021 09:54:47.965 # +sdown master redis-master 172.18.0.3 6379
redis-sentinel_3  | 1:X 09 Nov 2021 09:54:48.040 # +odown master redis-master 172.18.0.3 6379 #quorum 2/2
redis-sentinel_3  | 1:X 09 Nov 2021 09:54:48.040 # +new-epoch 1
redis-sentinel_3  | 1:X 09 Nov 2021 09:54:48.040 # +try-failover master redis-master 172.18.0.3 6379
redis-sentinel_2  | 1:X 09 Nov 2021 09:54:48.041 # +odown master redis-master 172.18.0.3 6379 #quorum 3/2

sdown vs odown

Master가 죽게되면 sentinel은 자신이 감시하고 있는 master가 죽었다고 sdown 시그널을 보낸다.

  • sdown(Subjective Down): 단지 Master와 sentinel 자신이 연결되지 않음을 의미함

다수결의 원칙에 따라 quorum 값 만큼 sdown이 발생하면 sentinel은 odown 시그널을 보낸다.

  • odown(Objective Down): 다수결에 의해 명시적으로 Master가 down되었음을 선포함 -> failover가 trigger됨 -> sentinel들은 다음 master를 선출하기 위해 남아있는 slave redis들에게 투표 진행 -> 더 많은 투표수를 받은 slave가 Master로 선출
# 2개의 sentinel에서 2개의 sdown이 감지되었으므로 odown 으로 판정한다는 뜻
+odown master redis-master 172.18.0.3 6379 #quorum 2/2
  1. wait_start: epoch를 증가시키고 장애 조치를 주관할 sentinel을 찾는다
  • +try-failover <instance details>
  • elected-leader: 센티널 리더 선출
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:26.055 # +new-epoch 1
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:26.055 # +try-failover master redis-master 172.18.0.3 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.059 # +vote-for-leader 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 1
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.059 # b3a6aa46758ee62eea71f3c738c9461dd8415241 voted for b3a6aa46758ee62eea71f3c738c9461dd8415241 1
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:26.059 # +vote-for-leader b3a6aa46758ee62eea71f3c738c9461dd8415241 1
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:26.059 # 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae voted for 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 1
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:26.066 # +new-epoch 1
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:26.070 # +vote-for-leader 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 1
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.070 # 3b007ba5996a3cd11c757cc48abacd5c6fc3616a voted for 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 1
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:26.070 # 3b007ba5996a3cd11c757cc48abacd5c6fc3616a voted for 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 1
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:26.099 # +odown master redis-master 172.18.0.3 6379 #quorum 3/2
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:26.099 # Next failover delay: I will not start a failover before Tue Nov  9 10:57:26 2021
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.111 # +elected-leader master redis-master 172.18.0.3 6379
  1. select_slave: 새로운 마스터가 될 복제를 선정한다.
  • failover-state-select-slave
  • selected-slave: 슬레이브 선정
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.111 # +failover-state-select-slave master redis-master 172.18.0.3 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.173 # +selected-slave slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
  1. send_slaveof_noone: 선정된 복제에게 SLAVEOF NO ONE 명령을 실행
  • failover-state-send-slaveof-noone: 승격된 replica가 master로 reconfigure되기를 시도
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.173 * +failover-state-send-slaveof-noone slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
  1. wait_promotion : SLAVEOF NO ONE 명령이 완료되기를 기다리는 상태
  • redis-replica | MASTER MODE enabled!!!!
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:26.307 * +failover-state-wait-promotion slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379

redis-sentinel_3  | 1:X 09 Nov 2021 10:51:27.664 # +sdown slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:27.673 # +sdown slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:27.674 # +sdown slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
redis-replica     | 1:S 09 Nov 2021 10:51:33.718 # Unable to connect to MASTER: Resource temporarily unavailable
redis-replica     | 1:M 09 Nov 2021 10:51:33.720 * Discarding previously cached master state.
redis-replica     | 1:M 09 Nov 2021 10:51:33.720 # Setting secondary replication ID to cd6da3c89085d43ca9043a0a8716dd8c260ac681, valid up to offset: 30704. New replication ID is 06b4d7adc106735504b2949e5037edef3e0e602c
redis-replica     | 1:M 09 Nov 2021 10:51:33.720 * MASTER MODE enabled (user request from 'id=13 addr=172.18.0.5:52707 laddr=172.18.0.2:6379 fd=10 name=sentinel-2d2a77f6-cmd age=0 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=6889 qbuf-free=34065 argv-mem=4 obl=4701 oll=0 omem=0 tot-mem=61468 events=r cmd=exec user=default redir=-1')
redis-replica     | 1:M 09 Nov 2021 10:51:33.724 # CONFIG REWRITE executed with success.

redis-sentinel_1  | 1:X 09 Nov 2021 10:51:33.729 # +promoted-slave slave 172.18.0.2:6379 172.18.0.2 6379 @ redis-master 172.18.0.3 6379
  1. reconf_slaves : 복제들에게 새 마스터를 바라보도록 SLAVEOF New-IP New-Port 명령을 실행한 상태.
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:33.729 # +failover-state-reconf-slaves master redis-master 172.18.0.3 6379
  • 원래는 replica개수만큼 아래와 같은 로그를 남긴다. 현재는 1 master - 1 replica라서 남지않음.
     18:00:24.982 * +slave-reconf-sent slave 127.0.0.1:7123 127.0.0.1 7123 @ mymaster01 127.0.0.1 7122
     18:00:25.969 * +slave-reconf-inprog slave 127.0.0.1:7123 127.0.0.1 7123 @ mymaster01 127.0.0.1 7122
     18:00:25.969 * +slave-reconf-done slave 127.0.0.1:7123 127.0.0.1 7123 @ mymaster01 127.0.0.1 7122
    
  1. update_config : 센티널이 가지고 있는 정보를 새 마스터와 복제로 갱신하고 새 마스터를 모니터링하기 시작
  • failover-end: failover가 성공적으로 끝남. 다른 replica들은 새로운 master로 바라보게 reconfigure됨.
  • switch-master <master name> <oldip> <oldport> <newip> <newport> master 승격완료~
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:33.732 # +config-update-from sentinel 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 172.18.0.5 26379 @ redis-master 172.18.0.3 6379
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:33.733 # +switch-master redis-master 172.18.0.3 6379 172.18.0.2 6379
redis-sentinel_2  | 1:X 09 Nov 2021 10:51:33.733 * +slave slave 172.18.0.3:6379 172.18.0.3 6379 @ redis-master 172.18.0.2 6379
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:33.733 # +config-update-from sentinel 2d2a77f6607c02f4c7f1c3a70db5c36b6d034aae 172.18.0.5 26379 @ redis-master 172.18.0.3 6379
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:33.733 # +switch-master redis-master 172.18.0.3 6379 172.18.0.2 6379
redis-sentinel_3  | 1:X 09 Nov 2021 10:51:33.733 * +slave slave 172.18.0.3:6379 172.18.0.3 6379 @ redis-master 172.18.0.2 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:33.808 # +failover-end master redis-master 172.18.0.3 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:33.808 # +switch-master redis-master 172.18.0.3 6379 172.18.0.2 6379
redis-sentinel_1  | 1:X 09 Nov 2021 10:51:33.808 * +slave slave 172.18.0.3:6379 172.18.0.3 6379 @ redis-master 172.18.0.2 6379

http://redisgate.kr/redis/sentinel/sentinel.php

장애조치(failover) 시 주의할 사항

  1. get-master-addr-by-name : 마스터,복제 모두 다운되었을 때, 센티널에 접속해서 마스터 서버 정보를 요청하면 이미 다운된 서버 정보를 리턴한다. 이 정보를 받은 클라이언트/어플리케이션은 이미 다운된 서버에 접속하려고 시도할 것이다. INFO sentinel 명령으로 마스터의 status를 확인해야 한다.
127.0.0.1:5000> sentinel get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6382"
127.0.0.1:5000> info sentinel
master0:name=mymaster,status=odown,address=127.0.0.1:6383,slaves=1,sentinels=1
  1. 복제 -> 마스터 승격 안되는 경우 복제가 먼저 다운되고, 마스터가 다운된 다음, 복제(6383)가 시작되면 이 서버는 마스터로 전환되지 않는다. 즉, 복제의 redis.conf 에 자신이 복제로 되어 있고, 센티널도 이 서버(6383)를 복제라고 인식하고 있을 경우 마스터로 전환하지 않는다. 해결책은 복제(6383)을 시작하기 전에 redis.conf 에서 slaveof 를 삭제하는 것이다

참고

https://redis.io/topics/sentinel http://redisgate.kr/redis/sentinel/sentinel_info.php

http://redisgate.kr/redis/sentinel/sentinel_masters.php

https://jaehun2841.github.io/2018/12/02/2018-12-02-docker-7 https://devops.sdsdev.co.kr/confluence/pages/viewpage.action?pageId=94386973


더 찾아봐야하럿

  • 영속성유지의 방법은 AOF, RDB방식이 존재하는데, 잦은 재기동이 필요한 환경(kubernetes나 docker)에는 AOF 방식이 유리하다.

  • Redis5 -> Redis6의 주요 기능은 보안관련인데, TLS통신관련과 ACL기능이 들어와있다.

  • https://redis.io/topics/sentinel#example-sentinel-deployments

redis.conf는 어디있지?? sentinel.conf는 sentinel container의 /bitnami/redis-sentinel/conf에 있음.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment