Database/Redis

[Redis] 센티넬을 사용한 자동 Failover 방법 (Failback 포함)

꽁담 2020. 3. 19. 03:19

센티넬의 자동 Failover 기능



센티넬은 마스터, 복제서버가 정상적인지 감지하고 있다가

마스터 서버가 다운되면 복제서버를 자동으로 마스터로 승격시켜 주는 기능을 수행합니다.



센티넬 Failover 테스트


센티넬이 모니터링 하고 있는 서버

모든 레디스는 하나의 서버에 구성되어 있어서 포트로만 구분하였습니다.

마스터 6379

복제1 6380

복제2 6381

센티넬 8000


1. 마스터 서버 shutdown

1
2
$ redis-cli -6379
127.0.0.1:6379> shutdown
cs


2. 마스터 된 서버의 info replication 확인

복제1(6380) 서버에서 확인을 했으며 복제2(6381) 서버가 마스터로 승격된 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:211578
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:dd339f267cdeadf15cbf1f87e6f811844a86382f
master_replid2:8c31c5db1645b18ee1888127c8687d4e82135ab2
master_repl_offset:211578
second_repl_offset:185284
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:211578
cs


3. 센티넬 서버의 info sentinel 확인

master 의 포트가 6381로 변경된 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
$ redis-cli -8000
127.0.0.1:8000> 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=127.0.0.1:6381,slaves=2,sentinels=1
cs



Failover 시 로그


센티넬 8000 로그

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2676:X 19 Mar 2020 01:51:26.336 # +sdown master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.336 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
2676:X 19 Mar 2020 01:51:26.336 # +new-epoch 1
2676:X 19 Mar 2020 01:51:26.336 # +try-failover master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.342 # +vote-for-leader f04fbcf3a4a9cb19ef63221e20c39c39d5b6e5c9 1
2676:X 19 Mar 2020 01:51:26.342 # +elected-leader master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.342 # +failover-state-select-slave master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.449 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.449 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:26.535 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:27.367 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:27.367 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:27.465 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:28.375 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:28.375 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:28.436 # +failover-end master mymaster 127.0.0.1 6379
2676:X 19 Mar 2020 01:51:28.436 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381
2676:X 19 Mar 2020 01:51:28.436 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381
2676:X 19 Mar 2020 01:51:28.436 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
2676:X 19 Mar 2020 01:51:33.467 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
cs


Line 1 : sdown 이 수행되었습니다.

Line 2 : odown 이 수행되었습니다.

Line 8 : 복제2(6381) 서버가 Failover 대상으로 지정되었습니다.

Line 9 : slaveof noone 명령어로 복제2(6381) 서버를 마스터로 승격시킵니다.

Line 17 : 복제2(6381) 서버로 마스터가 변경되었습니다.

Line 18 - 20 : 6379 서버를 sentinel conf 파일에 복제서버로 기록하였습니다.


* sdown (Subjectively down) : 주관적 다운이라고 불리며, 센티넬 한 대에서만 통신이 되지 않는다고 판단한 것입니다.

정족수를 만족하지 않는 경우 failover는 진행되지 않습니다.

* odown (Objectively down) : 객관적 다운이라고 불리며, 설정한 정족수를 만족하게 되어 실제 failover가 발생합니다.


복제1 6380 로그

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2130:S 19 Mar 2020 01:51:21.207 # Connection with master lost.
2130:S 19 Mar 2020 01:51:21.207 * Caching the disconnected master state.
2130:S 19 Mar 2020 01:51:21.927 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:21.927 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:21.927 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:22.954 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:22.954 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:22.954 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:24.020 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:24.020 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:24.020 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:25.111 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:25.111 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:25.111 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:26.143 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:26.143 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:26.143 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:27.199 * Connecting to MASTER 127.0.0.1:6379
2130:S 19 Mar 2020 01:51:27.199 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:27.199 # Error condition on socket for SYNC: Connection refused
2130:S 19 Mar 2020 01:51:27.466 * REPLICAOF 127.0.0.1:6381 enabled (user request from 'id=8 addr=127.0.0.1:39162 fd=7 name=sentinel-f04fbcf3-cmd age=722 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=280 qbuf-free=32488 obl=36 oll=0 omem=0 events=r cmd=exec')
2130:S 19 Mar 2020 01:51:27.466 # CONFIG REWRITE executed with success.
2130:S 19 Mar 2020 01:51:28.251 * Connecting to MASTER 127.0.0.1:6381
2130:S 19 Mar 2020 01:51:28.251 * MASTER <-> REPLICA sync started
2130:S 19 Mar 2020 01:51:28.251 * Non blocking connect for SYNC fired the event.
2130:S 19 Mar 2020 01:51:28.251 * Master replied to PING, replication can continue...
2130:S 19 Mar 2020 01:51:28.252 * Trying a partial resynchronization (request 8c31c5db1645b18ee1888127c8687d4e82135ab2:185284).
2130:S 19 Mar 2020 01:51:28.252 * Successful partial resynchronization with master.
2130:S 19 Mar 2020 01:51:28.252 # Master replication ID changed to dd339f267cdeadf15cbf1f87e6f811844a86382f
2130:S 19 Mar 2020 01:51:28.252 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.
cs


Line 1 : 마스터와 연결이 끊어졌습니다.

Line 3 - 5 : Timeout 될때까지 1초간격으로 반복적으로 기록됩니다.

Line 21 : 복제2(6381) 서버가 마스터 서버로 변경되었습니다.

Line 22 : conf 파일을 새로운 서버 기준에 맞게 재 작성하였습니다.

Line 23 : 마스터로 승격된 6381 서버에 연결하였습니다.

Line 24 - 30 : 데이터 동기화를 재 수행 하였습니다.


복제2 6381 로그

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2139:S 19 Mar 2020 01:51:21.207 # Connection with master lost.
2139:S 19 Mar 2020 01:51:21.207 * Caching the disconnected master state.
2139:S 19 Mar 2020 01:51:21.413 * Connecting to MASTER 127.0.0.1:6379
2139:S 19 Mar 2020 01:51:21.413 * MASTER <-> REPLICA sync started
2139:S 19 Mar 2020 01:51:21.413 # Error condition on socket for SYNC: Connection refused
2139:S 19 Mar 2020 01:51:22.530 * Connecting to MASTER 127.0.0.1:6379
2139:S 19 Mar 2020 01:51:22.530 * MASTER <-> REPLICA sync started
2139:S 19 Mar 2020 01:51:22.531 # Error condition on socket for SYNC: Connection refused
2139:S 19 Mar 2020 01:51:23.586 * Connecting to MASTER 127.0.0.1:6379
2139:S 19 Mar 2020 01:51:23.586 * MASTER <-> REPLICA sync started
2139:S 19 Mar 2020 01:51:23.586 # Error condition on socket for SYNC: Connection refused
2139:S 19 Mar 2020 01:51:24.684 * Connecting to MASTER 127.0.0.1:6379
2139:S 19 Mar 2020 01:51:24.684 * MASTER <-> REPLICA sync started
2139:S 19 Mar 2020 01:51:24.684 # Error condition on socket for SYNC: Connection refused
2139:S 19 Mar 2020 01:51:25.779 * Connecting to MASTER 127.0.0.1:6379
2139:S 19 Mar 2020 01:51:25.780 * MASTER <-> REPLICA sync started
2139:S 19 Mar 2020 01:51:25.780 # Error condition on socket for SYNC: Connection refused
2139:M 19 Mar 2020 01:51:26.535 # Setting secondary replication ID to 8c31c5db1645b18ee1888127c8687d4e82135ab2, valid up to offset: 185284. New replication ID is dd339f267cdeadf15cbf1f87e6f811844a86382f
2139:M 19 Mar 2020 01:51:26.535 * Discarding previously cached master state.
2139:M 19 Mar 2020 01:51:26.535 * MASTER MODE enabled (user request from 'id=8 addr=127.0.0.1:46080 fd=7 name=sentinel-f04fbcf3-cmd age=721 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=140 qbuf-free=32628 obl=36 oll=0 omem=0 events=r cmd=exec')
2139:M 19 Mar 2020 01:51:26.537 # CONFIG REWRITE executed with success.
2139:M 19 Mar 2020 01:51:28.252 * Replica 127.0.0.1:6380 asks for synchronization
2139:M 19 Mar 2020 01:51:28.252 * Partial resynchronization request from 127.0.0.1:6380 accepted. Sending 287 bytes of backlog starting from offset 185284.
cs


Line 21 : conf 파일을 새로운 서버 기준에 맞게 다시 작성하였습니다.

Line 22 : 복제1(6380) 서버가 동기화를 요청하였습니다.

Line 23 : 복제1(6380) 서버에 동기화를 진행합니다.



센티넬 FailBack 테스트


1. 6379 서버 구동

1
$ redis-server redis_6379.conf
cs


2. 6379 서버에서 info replication 으로 복제 구성 확인

6381 서버를 마스터로 바라보고 있음을 알 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ redis-cli -6379
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:310067
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:dd339f267cdeadf15cbf1f87e6f811844a86382f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:310067
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:301429
repl_backlog_histlen:8639
cs


3. 6379 서버로 마스터 승격 & 복제 구성 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
 
127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:332860
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:1d3b105a1c8941c629413a18bc7b274a7e75e2bf
master_replid2:dd339f267cdeadf15cbf1f87e6f811844a86382f
master_repl_offset:332860
second_repl_offset:332032
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:332846
cs



Failback 시 로그


6379 서버가 다시 구동될 때의 로그

6379 로그

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2939:S 19 Mar 2020 02:20:41.291 * REPLICAOF 127.0.0.1:6381 enabled (user request from 'id=3 addr=127.0.0.1:42280 fd=8 name=sentinel-f04fbcf3-cmd age=10 idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=148 qbuf-free=32620 obl=36 oll=0 omem=0 events=r cmd=exec')
2939:S 19 Mar 2020 02:20:41.293 # CONFIG REWRITE executed with success.
2939:S 19 Mar 2020 02:20:42.235 * Connecting to MASTER 127.0.0.1:6381
2939:S 19 Mar 2020 02:20:42.235 * MASTER <-> REPLICA sync started
2939:S 19 Mar 2020 02:20:42.235 * Non blocking connect for SYNC fired the event.
2939:S 19 Mar 2020 02:20:42.235 * Master replied to PING, replication can continue...
2939:S 19 Mar 2020 02:20:42.236 * Trying a partial resynchronization (request b6560d68266ca61ce897c4b452228916c2bd1d88:1).
2939:S 19 Mar 2020 02:20:42.237 * Full resync from master: dd339f267cdeadf15cbf1f87e6f811844a86382f:301428
2939:S 19 Mar 2020 02:20:42.237 * Discarding previously cached master state.
2939:S 19 Mar 2020 02:20:42.341 * MASTER <-> REPLICA sync: receiving 242 bytes from master
2939:S 19 Mar 2020 02:20:42.342 * MASTER <-> REPLICA sync: Flushing old data
2939:S 19 Mar 2020 02:20:42.348 * MASTER <-> REPLICA sync: Loading DB in memory
2939:S 19 Mar 2020 02:20:42.348 * MASTER <-> REPLICA sync: Finished with success
2939:S 19 Mar 2020 02:20:42.348 * Background append only file rewriting started by pid 2947
2939:S 19 Mar 2020 02:20:42.391 * AOF rewrite child asks to stop sending diffs.
2947:C 19 Mar 2020 02:20:42.391 * Parent agreed to stop sending diffs. Finalizing AOF...
2947:C 19 Mar 2020 02:20:42.391 * Concatenating 0.00 MB of AOF diff received from parent.
2947:C 19 Mar 2020 02:20:42.397 * SYNC append only file rewrite performed
2947:C 19 Mar 2020 02:20:42.398 * AOF rewrite: 0 MB of memory used by copy-on-write
2939:S 19 Mar 2020 02:20:42.436 * Background AOF rewrite terminated with success
2939:S 19 Mar 2020 02:20:42.436 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB)
2939:S 19 Mar 2020 02:20:42.436 * Background AOF rewrite finished successfully
cs


Line 1 : 6381 서버의 복제서버로 사용이 가능합니다.

Line 2 : conf 파일을 rewrite 합니다.

Line 3 : 마스터 서버인 6381 서버에 연결합니다.

Line 4 - 22 : 동기화 작업을 진행합니다.


6381 로그

1
2
3
4
5
6
7
8
2139:M 19 Mar 2020 02:20:42.236 * Replica 127.0.0.1:6379 asks for synchronization
2139:M 19 Mar 2020 02:20:42.236 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for 'b6560d68266ca61ce897c4b452228916c2bd1d88', my replication IDs are 'dd339f267cdeadf15cbf1f87e6f811844a86382f' and '8c31c5db1645b18ee1888127c8687d4e82135ab2')
2139:M 19 Mar 2020 02:20:42.236 * Starting BGSAVE for SYNC with target: disk
2139:M 19 Mar 2020 02:20:42.236 * Background saving started by pid 2944
2944:C 19 Mar 2020 02:20:42.248 * DB saved on disk
2944:C 19 Mar 2020 02:20:42.248 * RDB: 0 MB of memory used by copy-on-write
2139:M 19 Mar 2020 02:20:42.341 * Background saving terminated with success
2139:M 19 Mar 2020 02:20:42.341 * Synchronization with replica 127.0.0.1:6379 succeeded
cs


Line 1 : 6379 서버가 동기화를 요청합니다.

Line 8 : 6379 서버에 동기화 작업이 완료되었습니다.


센티넬 로그

1
2
2676:X 19 Mar 2020 02:20:31.363 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
2676:X 19 Mar 2020 02:20:41.291 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381
cs


Line 1 : 6379 서버가 통신이 성공하였습니다.

Line 2 : 6379 서버를 복제서버로 변경하였습니다.


FailBack 에 대한 로그는 지난번 다른 FailBack 방식의 로그이기 때문에 따로 정리하지는 않습니다.

(센티넬은 내용이 조금 기록되지만 따로 정리하지는 않았으며 서버 로그내용 보시고 이해하는데 어렵지는 않을 것 같습니다.)



장애조치에서 주의할 사항


복제에서 마스터로 승격되지 않는 경우

복제가 마스터보다 먼저 다운되고, 마스터가 다운되는 경우에

복제 서버가 먼저 올라오면 마스터로 전환되지 않습니다.


왜냐하면 복제서버 conf 파일에 복제서버로 설정되어 있고,

센티넬에서도 이 서버를 복제라고 인식하고 있기 때문입니다.


이런경우 복제서버 conf 파일에서 slaveof 를 삭제 후 구동을 해주어야 합니다.


Failover 시 복제서버의 후보 선정 기준

센티넬은 1차 복제중에서만 마스터의 후보에 오를 수 있습니다.

즉, 복제 서버의 복제 서버는 마스터의 후보에 오를 수 없습니다.


1차 복제서버중 conf 파일에 있는 replica-priority 값이 가장 작은 값을 가진 서버가 마스터에 선정됩니다.

0으로 설정할 수 있는데 이 경우에는 마스터로 승격되지 않습니다.

같은 값을 가지는 경우에 대해서는 엔진에서 선택하게 됩니다.


마스터와 1차복제서버가 거의 동시에 다운되었을 때 2차복제서버는 마스터로 승급 불가

위에서 마스터 다운시 2차복제서버는 Failover 대상이 아님을 정리하였습니다.

만약 마스터와 1차복제서버가 동시에 다운되는 경우 센티넬에서는 2차복제서버를 알지 못해 마스터로 승급하지 못합니다.


만약 마스터와 1차복제서버간에 다운타임의 충분한 차이가 있으면

센티넬에서는 1차복제서버를 마스터로 승격하면서 2차복제서버의 정보를 얻어올 수 있고,

1차복제서버가 다운되면 2차복제서버를 마스터로 승급시킬 수 있게 됩니다.


 1차

 2차

 3차

 Master

 -

 -

 Slave1

 Master

 -

 Slave1 의 Slave1

 Slave1

 Master


쿼럼의 정족수

쿼럼값이 1인 경우, 오탐으로 인해서도 Failover 가 발생할 가능성이 있기 때문에 2로 설정하는 게 좋습니다.

2로 설정하고 센티넬서버가 2대인 경우, 하나의 센티넬 서버가 장애가 발생하면 Failover 는 정족수를 채우지 못해 발생하지 않습니다.


따라서 2값을 유지하면서 센티넬 서버는 3대를 유지하는게 좋습니다.