Redis Sentinel Failover Full Resync 현상 분석 및 대응 방안

taeni·2026년 3월 19일

Redis Sentinel Failover Full Resync 현상 분석 및 대응 방안

환경: Redis 6.0 / Sentinel / 데이터 500GB 이상


1. 현상

Sentinel에서 sentinel failover mymaster 명령어로 수동 failover를 수행하면, 데이터가 거의 없고 backlog 설정이 충분한 환경에서도 partial resync가 아닌 full resync가 발생한다.

발생 로그

Before turning into a replica, using my own master parameters to synthesize a cached master:
I may be able to synchronize with the new master with just a partial transfer
Discarding previously cached master state.
Full resync from master
connection with replica client id lost

환경 정보

  • Redis 버전: 6.0
  • 데이터 사용량: 500GB 이상 (프로덕션)
  • client-output-buffer-limit (slave): 2GB 1GB 60
  • repl-timeout: 600초
  • repl-backlog-size: 충분히 큰 값으로 설정됨
  • master_replid2: 0000000000000000000000000000000000000000 (초기화됨)

2. 원인 분석

2.1 근본 원인: sentinel failover의 구조적 한계

sentinel failover는 내부적으로 선택된 replica에게 SLAVEOF NO ONE을 보내는 비협조적(uncoordinated) 방식이다. master는 자신이 교체될 것을 모르기 때문에 내부 쓰기를 계속하고, 이로 인해 offset 불일치가 발생한다. 이것은 버전과 관계없이 동일하게 발생하는 구조적 문제이다.

2.2 Failover 시 내부 동작 순서

  1. Sentinel이 replica를 선택하여 SLAVEOF NO ONE 전송 → 새 master로 승격
  2. 새 master는 새로운 replid 생성, 이전 replid를 replid2에 저장, second_repl_offset 기록
  3. 이전 master는 아직 master로 동작 중 → 내부 쓰기(expire, Sentinel PING 등)로 offset 계속 증가
  4. Sentinel이 이전 master에게 SLAVEOF <new-master> 전송 → replica로 전환
  5. 기존 replication 연결 끊김 → connection with replica client id lost 발생
  6. 이전 master가 새 master에게 PSYNC 요청 → 자신의 offset이 새 master의 second_repl_offset보다 큼
  7. 새 master가 partial resync 거부 → full resync 발생

2.3 핵심 메커니즘: Offset 불일치

이전 master의 offset이 새 master의 second_repl_offset보다 크면, 새 master는 "이 replica가 요청하는 offset은 내가 알고 있는 분기 시점보다 앞서 있다"고 판단하여 partial resync를 거부한다. 데이터가 거의 없는 환경에서도 failover 과정의 시간 차이 동안 Sentinel의 PING/INFO 교환만으로 offset 차이가 발생한다.

2.4 replid2 초기화는 결과이지 원인이 아님

master_replid2가 000...000으로 보이는 것은 full resync가 완료된 후 replica가 새 master의 replid로 갱신되면서 초기화된 결과이다.

2.5 배제된 원인

  • backlog 크기 부족 → 설정 충분 + 데이터 거의 없음
  • client-output-buffer-limit → 2GB로 충분
  • repl-timeout → 600초로 충분
  • backlog 덮어쓰기 → 쓰기 거의 없음

3. 500GB 환경에서 Full Resync의 영향

  • RDB fork 시 copy-on-write로 메모리 사용량 최대 2배(~1TB) → OOM killer 위험
  • RDB 생성 중 수십 분간 CPU/IO 부하
  • 500GB RDB 전송 중 네트워크 대역폭 점유
  • replica가 sync 완료할 때까지 수 시간 서비스 불안정
  • offset 차이만큼 데이터 유실 가능성

4. 대응 방안: CLIENT PAUSE + SENTINEL FAILOVER

버전과 관계없이 Sentinel 환경에서는 CLIENT PAUSE WRITE로 쓰기를 먼저 중단하여 master의 offset 증가를 멈춘 후 SENTINEL FAILOVER를 수행해야 한다. 이렇게 하면 새 master의 second_repl_offset과 이전 master의 offset이 일치하여 partial resync가 가능해진다.

Sentinel이 failover 주체가 되므로 +switch-master 이벤트가 즉시 발행되고, 클라이언트 전환도 정상적으로 이루어진다.

4.1 수동 수행 절차

사전 준비로 터미널 2개를 미리 준비한다.

  • 터미널 A: master 접속 (redis-cli -h <master-ip> -p 6379)
  • 터미널 B: sentinel 접속 (redis-cli -h <sentinel-ip> -p 26379)
순서터미널명령어설명
1A (master)INFO replicationslave0의 lag=0 확인 (0과 1 반복은 정상)
2B (sentinel)SENTINEL failover mymaster 타이핑만 (엔터 치지 않음)미리 준비
3A (master)CLIENT PAUSE 30000 WRITEOK 확인 후 즉시 Step 4
4B (sentinel)엔터 (미리 타이핑한 명령 실행)Step 3과 간격 최소화
5A (master)INFO replicationrole:slave 변경 확인
6A (master)CLIENT UNPAUSE안전하게 해제

4.2 핵심 포인트

  • Step 3과 Step 4 사이 간격을 최대한 짧게 하는 것이 핵심이다.
  • PAUSE timeout 30초는 안전장치이다. failover가 실패해도 30초 후 자동으로 쓰기가 재개된다.
  • lag이 0과 1을 오가는 것은 정상이다. lag은 replica가 1초마다 ACK를 보내는 타이밍 기반이므로, offset 차이가 수십~수백 이내면 바로 진행해도 된다.
  • CLIENT PAUSE를 안 해도 failover 중에는 어차피 쓰기가 안 되므로, CLIENT PAUSE가 추가하는 쓰기 중단 시간은 사실상 없다.

4.3 예상 클라이언트 영향 비교

구분CLIENT PAUSE + failover그냥 sentinel failover
쓰기 중단 시간약 5~10초약 5~10초 (비슷)
failover 후 상태partial resync → 즉시 정상full resync → 수 시간 부하
master 부하없음RDB fork로 메모리/CPU/IO 폭증
OOM 위험없음copy-on-write로 최대 ~1TB
replica 가용성즉시 정상sync 완료까지 불안정
데이터 정합성보장offset 차이만큼 유실 가능

5. SENTINEL FAILOVER vs CLUSTER FAILOVER

Redis Cluster 환경의 CLUSTER FAILOVER는 이 문제가 발생하지 않는다. replica가 master에게 failover를 요청하면 master가 CLIENT PAUSE WRITE를 실행하고, replica가 offset을 따라잡은 후 Cluster 투표를 통해 전환된다. 협조적(coordinated) 방식이므로 offset 불일치가 없고, Cluster 구성이 자동 전파되어 추가 조치도 불필요하다.

Sentinel 환경의 SENTINEL FAILOVER는 master에게 알리지 않고 replica에 SLAVEOF NO ONE을 보내는 비협조적 방식이므로 offset 불일치가 발생하며, 이를 방지하려면 수동으로 CLIENT PAUSE WRITE를 먼저 수행해야 한다. 이 문제는 Sentinel이 내부적으로 협조적 전환을 지원하지 않는 구조적 한계이며, GitHub issue #13118, #13917에서 개선이 제안된 상태이나 아직 공식 반영되지 않았다.


6. 로그 확인 방법

6.1 Failover 전후 replication 상태 확인

redis-cli -h <노드-ip> INFO replication

확인할 값: master_replid, master_replid2, master_repl_offset, second_repl_offset, repl_backlog_first_byte_offset

6.2 새 master 로그에서 partial resync 거부 사유 확인

grep -iE "psync|partial|full|resync|replid|offset|accept|reject" <new-master-log-path>

다음 중 하나가 출력된다:

  • Partial resynchronization not accepted: Replication ID mismatch → replid 불일치
  • Partial resynchronization not accepted: Requested offset for second ID was X, but I can reply up to Y → offset 초과

6.3 이전 master(강등된 노드) 로그 확인

grep -iE "psync|partial|full|resync|cached|discard|turning|pause" <old-master-log-path>

6.4 Sentinel 로그에서 failover 진행 확인

grep -iE "failover|switch-master|promoted|selected" <sentinel-log-path>

7. 근거 문서

profile
정태인의 블로그

0개의 댓글