가용성이란, 서버와 네트워크 또는 프로그램 등의 다양한 시스템이 정상적으로 사용 가능한 정도를 의미한다.
고가용성은, 쉽게 말하자면 가용성이 매우 높은 정도를 말한다. 다르게 말하면, 시스템에 장애가 발생해도 찰나의 순간에 이를 감지하고 복구하거나 미리 백업된 시스템이 이를 대체하여 사용자에게 연속적인 서비스를 제공하게 하는 것을 의미한다.
시스템의 가용성을 높이기 위해 장비를 다중화시키는 방법을 이중화라고 한다. HA와 밀접한 관계에 있다. 이중화의 대상은 웹 서버, 데이터베이스, 네트워크 라우터 등의 하드웨어가 될 수도 있고, 프로세스 상태로 실행 중인 소프트웨어가 대상이 될 수도 있다. 즉, 사용자에게 서비스를 제공하기 위해 필요한 모든 컴포넌트가 이중화의 대상이 된다.
이중화의 종류는 다음과 같다.
이중화된 장비가 모두 가동되는 방식이다. 동시에 모든 장비가 작동하므로 처리할 수 있는 작업의 양이 상대적으로 많다.
두 개 중 메인이 되는 Active 장비 하나만 작동하고, 나머지 하나는 Active의 장애 상황에 대비하여 Standby 상태로 대기한다.
Active 장비에 장애가 발생하여 작동 불능인 경우, Standby 장비가 Active 상태로 전환하여 작업을 대신 하는데, 이 과정을 failover(장애복구)라고 한다.
고가용성을 최대한 보장하기 위해서는 Standby가 Active로 전환되는 Delay 시간을 줄여야 한다. 따라서 Active의 상태를 주기적으로 확인(Health Check)하기 위한 모니터링 시스템과, Standby의 상태를 자동으로 Active로 전환해주는 시스템이 필요하다.
Redis는 Key-Value 구조의 데이터를 저장하는 인메모리(In-Memory) 기반의 비관계형 데이터베이스 시스템(NoSQL)이다.
$ wget https://github.com/redis/redis/archive/7.0.10.tar.gz
$ tar -xzf 7.0.10.tar.gz
$ cd redis-7.0.10
redis-7.0.10 $ make install
이후 src/
디렉토리 아래에 redis-cli
, redis-server
, redis-sentinel
등 여러 바이너리 파일이 생성된다.
Redis는 데이터를 백업하고 이중화하기 위해 Active-Standby의 구조로 사용할 수 있다. 이때 Active는 Master
, Standby는 Replica
라고 한다.
과거에는 Standby를 'Slave'라고 불렀다. 하지만 Redis 5 버전부터 Slave 대신 Replica로 용어가 변경되었다.
보통 Master-Slave 구조라고 하면 Master-Replica 구조와 같다.
구분 | 읽기 | 쓰기 |
---|---|---|
Master | 가능 | 가능 |
Replica | 가능 | 불가능 (옵션에 따라 가능하게 할 수 있지만 권장하지 않음.) |
$ cp redis.conf redis_6379.conf
$ vim redis_6379.conf
# redis_6379.conf for MASTER
port 6379
daemonize yes
logfile logs/redis_6379.log
requirepass asdf
$ cp redis.conf redis_6380.conf
$ vim redis_6380.conf
# redis_6380.conf for REPLICA
port 6380
daemonize yes
logfile logs/redis_6380.log
requirepass asdf
replicaof 127.0.0.1 6379
masterauth asdf
$ src/redis-server redis_6379.conf
$ src/redis-server redis_6380.conf
$ ps -e | grep redis
58958 ?? 0:03.96 src/redis-server 127.0.0.1:6379
59343 ?? 0:00.51 src/redis-server 127.0.0.1:6380
$ tail -f logs/redis_6379.log
$ tail -f logs/redis_6380.log
$ src/redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth asdf
OK
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=2730,lag=1
$ src/redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth asdf
OK
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
Redis가 Master-Replica 구조로 작동한다고 해도, Master가 다운되면 Replica는 Master가 다운되었음을 감지하지만 자기 혼자서 Master로 올라가지 않고 그대로 있다. Master와 Replica의 상태를 주기적으로 모니터링하고, Master가 다운되었으면 절차를 거쳐 Replica를 Master로 전환하는 역할을 하는 프로그램이 Redis Sentinel이다.
Sentinel의 역할은 다음과 같다.
Sentinel이 Master의 다운을 감지하고 failover하는 과정은 다음과 같다.
Sentinel은 모니터링 대상으로 지정된 Master 서버에 주기적으로 PING
명령을 보낸다.
어떤 Sentinel이 보낸 Heartbeat에서 down-after-milliseconds
동안 응답이 없으면 그 Sentinel은 해당 Master가 다운되었다고 주관적 다운(+sdown
) 판정을 내린다. 이때 주관적 판정이라고 부르는 이유는, 아직 다른 Sentinel들도 Master가 다운되었다고 판단하지 않았을 수 있기 때문이다.
주관적 다운 판정을 내린 Sentinel은 다른 Sentinel들에게 해당 Master가 다운되었는지 확인한다. 문의를 받은 Sentinel은 Master의 다운 여부를 응답한다. 다운되었다고 응답한 수가 지정된 수 이상이면, Sentinel은 Master가 다운되었다고 객관적으로 판정을 내린다(+odown
). 이때 객관적 다운의 기준이 되는 정족수를 Quorum이라고 한다.
Quorum은 Sentinel들의 과반수 등 고정된 값이 아니라, 임의로 설정 파일을 통해 지정할 수 있다. 대체적으로 과반수를 Quorum으로 지정하기는 한다.
Sentinel들은 Master 장애 복구 조치(failover)를 진행할 Leader Sentinel을 선출한다.
기존 Replica들 중 Master가 될 수 있는 기준을 만족하는 Replica들 중의 하나를 새로운 Master로 선정 후 전환한다.
이후 다른 Replica들이 새로운 Master를 바라보게 한다.
Sentinel은 1개로도 실행이 가능하지만, 오탐의 가능성이 있으므로 최소 3개 이상의 홀수개 구성을 권장한다.
5000, 5001, 5002 각각 생성.
$ cp sentinel.conf sentinel_{portNo}.conf
$ vim sentinel_{portNo}.conf
port #portNo
daemonize yes
logfile "logs/sentinel_{portNo}.log"
dir "/Users/bambookim/Downloads/redis-7.0.10"
sentinel monitor mymaster 127.0.0.1 6379 2 # 여기서 마지막 2는 quorum 값 지정
sentinel down-after-milliseconds mymaster 3000
sentinel auth-pass mymaster asdf
$ src/redis-sentinel sentinel_5000.conf
$ src/redis-sentinel sentinel_5001.conf
$ src/redis-sentinel sentinel_5002.conf
$ kill -9 {pid_master}
$ tail -f logs/sentinel_{portNo}.log
62839:X 29 Mar 2023 21:52:37.628 # +sdown master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.692 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2
62839:X 29 Mar 2023 21:52:37.693 # +new-epoch 3
62839:X 29 Mar 2023 21:52:37.693 # +try-failover master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.699 * Sentinel new configuration saved on disk
62839:X 29 Mar 2023 21:52:37.700 # +vote-for-leader 900642d4fc0a157edb167454cb47409fc10c78cf 3
62839:X 29 Mar 2023 21:52:37.721 # 6c585a651f6ebf897b89ae894d78b9556f4b3431 voted for 900642d4fc0a157edb167454cb47409fc10c78cf 3
62839:X 29 Mar 2023 21:52:37.722 # df63a49374a65a162406e32a2bfda3824221a2f8 voted for 900642d4fc0a157edb167454cb47409fc10c78cf 3
62839:X 29 Mar 2023 21:52:37.801 # +elected-leader master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.802 # +failover-state-select-slave master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.904 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.905 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:37.964 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:38.715 * Sentinel new configuration saved on disk
62839:X 29 Mar 2023 21:52:38.716 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:38.716 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:38.773 # +failover-end master mymaster 127.0.0.1 6379
62839:X 29 Mar 2023 21:52:38.774 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
62839:X 29 Mar 2023 21:52:38.774 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
62839:X 29 Mar 2023 21:52:38.780 * Sentinel new configuration saved on disk
62839:X 29 Mar 2023 21:52:41.848 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
$ src/redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth asdf
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:fc86e80307b5e937c8bbcc80c7f155a27696cbb4
master_replid2:4a3138252dfdcd6e67dbef9cface20cbc667ff5d