복제와 센티넬(고가용성)
Redis 고가용성의 기본 전제
Redis에서 고가용성을 말할 때 가장 먼저 나눠야 할 것은 복제(replication) 와 자동 장애 조치(failover) 다. 복제는 master의 데이터를 replica로 따라가게 하는 데이터 전달 메커니즘이고, Sentinel은 master 장애를 감지해 replica 중 하나를 새 master로 승격시키는 운영 제어면이다.
중요한 점은 Redis 복제가 기본적으로 비동기(asynchronous) 라는 것이다. master는 쓰기 명령을 처리한 뒤 replica가 모두 반영할 때까지 기다리지 않고 클라이언트에 응답한다. 그래서 Sentinel을 붙였다고 해서 Redis가 강한 일관성의 CP 저장소가 되는 것은 아니다. 장애 조치 시점에 아직 replica로 전달되지 않은 쓰기는 유실될 수 있다.
운영 관점에서 이 장의 결론은 단순하다.
- 복제만으로는 고가용성이 아니다. master가 죽으면 누가 승격할지, 클라이언트가 어디로 재접속할지 정해야 한다.
- Sentinel만으로 데이터 손실이 사라지지 않는다. 비동기 복제의 한계와 지속성 설정을 함께 봐야 한다.
- 클라이언트가 Sentinel을 이해해야 한다. 장애 조치 후 기존 master 주소에 계속 붙는 클라이언트는 HA 구성의 일부가 아니다.
복제 흐름: full sync와 partial sync
Redis replica는 master에 연결한 뒤 master의 데이터셋을 따라간다. 정상 연결 상태에서는 master가 쓰기 명령 스트림을 replica로 계속 보낸다. 네트워크가 잠깐 끊겼다가 복구되면 replica는 자신이 마지막으로 처리한 복제 offset을 기준으로 빠진 부분만 요청하려고 한다. 이것이 partial resynchronization이다.
partial sync가 가능하려면 master가 replica가 놓친 구간을 replication backlog에 아직 보관하고 있어야 한다. backlog가 부족하거나 replica가 알던 복제 이력이 master에서 더 이상 유효하지 않으면 full resynchronization이 발생한다.
full sync는 비용이 크다.
- master가 RDB 스냅샷을 만든다.
- replica로 전체 RDB를 전송한다.
- replica가 기존 데이터를 버리고 새 RDB를 로드한다.
- 그동안 master가 버퍼링한 쓰기 스트림을 이어서 반영한다.
데이터셋이 크면 full sync는 네트워크, 디스크, CPU, 메모리 copy-on-write 비용을 동시에 만든다. 장애 후 replica가 한꺼번에 재동기화되는 상황에서는 Redis 자체보다 주변 네트워크나 디스크가 먼저 병목이 될 수 있다.
운영자가 봐야 할 복제 상태
복제 상태는 INFO replication과 ROLE로 확인한다.
INFO replication
ROLEmaster에서 봐야 할 대표 지표는 다음과 같다.
| 지표 | 의미 | 운영 판단 |
|---|---|---|
role:master | 현재 인스턴스 역할 | 의도한 노드가 master인지 확인 |
connected_slaves | 연결된 replica 수 | 기대 replica 수보다 적으면 HA 위험 |
master_repl_offset | master 복제 스트림 offset | replica offset과 차이를 비교 |
repl_backlog_active | backlog 활성 여부 | partial sync 가능성에 영향 |
repl_backlog_size | backlog 크기 | 네트워크 단절 허용 시간과 관련 |
replica에서는 master와 연결 상태를 본다.
| 지표 | 의미 | 운영 판단 |
|---|---|---|
role:slave / role:replica | replica 역할 | Redis 프로토콜에는 호환성 때문에 slave 표현이 남아 있다 |
master_host, master_port | 따라가는 master | 장애 조치 후 새 master로 바뀌었는지 확인 |
master_link_status | master 연결 상태 | down이면 복제 중단 |
slave_repl_offset | replica가 받은 offset | master와 lag 계산 |
master_sync_in_progress | full sync 진행 여부 | 재동기화 중 부하 가능성 |
ROLE은 클라이언트가 실제 연결 대상이 master인지 검증할 때도 중요하다. Sentinel에서 master 주소를 받았더라도 정보가 잠깐 stale할 수 있기 때문에, 잘 만든 Sentinel-aware client는 Redis에 접속한 뒤 ROLE로 역할을 다시 확인한다.
WAIT: 데이터 손실 확률을 낮추는 도구
Redis에는 WAIT 명령이 있다.
SET order:1 paid
WAIT 1 1000WAIT 1 1000은 현재 연결에서 이전에 보낸 쓰기가 최소 1개 replica에 전달되어 acknowledgment를 받을 때까지 최대 1000ms 기다린다. 반환값은 실제로 acknowledge한 replica 수다. 따라서 클라이언트는 반환값이 기대값 이상인지 확인해야 한다.
하지만 WAIT는 Redis를 강한 일관성 저장소로 바꾸지 않는다. 공식 문서도 Sentinel 또는 Cluster failover 상황에서 WAIT가 현실적인 데이터 안전성을 높이지만, best-effort에 가깝고 쓰기 유실 가능성을 완전히 없애지는 않는다고 설명한다. 예를 들어 replica가 쓰기를 받았더라도 해당 replica가 승격되지 않거나, replica의 지속성 설정 때문에 재시작 과정에서 데이터가 사라질 수 있다.
실무에서는 다음처럼 판단한다.
- 캐시:
WAIT없이 낮은 지연시간을 우선한다. - 세션·락·일회성 토큰: 유실 비용을 보고
WAIT 1 <짧은 timeout>을 선택적으로 쓴다. - 결제·원장 같은 핵심 데이터: Redis 단독 저장을 피하고, DB 커밋 이후 캐시/큐 용도로 Redis를 둔다.
Sentinel이 하는 일
Sentinel은 일반 Redis 데이터 노드가 아니라 감시와 조정 역할을 하는 별도 프로세스다. 기본 포트는 26379다.
Sentinel의 역할은 네 가지로 정리된다.
- Monitoring: master와 replica가 응답하는지 계속 확인한다.
- Notification: 장애나 상태 변화를 API와 Pub/Sub 이벤트로 알린다.
- Automatic failover: master 장애 시 replica를 승격하고 다른 replica를 새 master에 붙인다.
- Configuration provider: 클라이언트가 현재 master 주소를 질의하는 discovery endpoint가 된다.
최소 설정은 다음과 같은 형태다.
# sentinel.conf
port 26379
sentinel monitor mymaster 10.0.0.10 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1여기서 mymaster는 클라이언트와 Sentinel이 공유하는 논리 서비스 이름이다. IP와 포트는 현재 master 주소다. 마지막 숫자 2는 quorum이다.
quorum과 majority를 구분해야 한다
Sentinel에서 자주 헷갈리는 부분은 quorum과 majority다.
quorum: master가 down이라고 판단하기 위해 동의해야 하는 Sentinel 수다.majority: 실제 failover를 진행하기 위해 필요한 Sentinel 전체의 과반 동의다.
예를 들어 Sentinel 5개, quorum 2라면 Sentinel 2개가 master를 down이라고 판단했을 때 장애 의심은 성립한다. 하지만 failover는 최소 3개 이상의 Sentinel이 접근 가능하고 권한을 부여해야 진행된다. Redis Sentinel 문서는 다수 Sentinel이 서로 통신할 수 없으면 failover를 시작하지 않는다고 설명한다. 이는 네트워크 파티션의 소수 쪽에서 새 master를 만들어 split brain을 일으키는 위험을 줄이기 위한 설계다.
그래서 Sentinel은 보통 3개 이상, 서로 다른 장애 도메인에 둔다. Sentinel 2개 구성은 피해야 한다. 한쪽 장애 시 남은 1개 Sentinel은 과반을 만들 수 없고, 잘못 구성하면 가용성과 안전성 모두 애매해진다.
장애 조치 흐름
master 장애가 발생하면 Sentinel은 대략 다음 순서로 움직인다.
- 각 Sentinel이 주기적으로 master에 ping을 보낸다.
down-after-milliseconds동안 유효 응답이 없으면 해당 Sentinel은 master를 주관적 다운(SDOWN) 으로 본다.- quorum 이상의 Sentinel이 동의하면 객관적 다운(ODOWN) 으로 본다.
- Sentinel들 사이에서 failover를 수행할 leader를 정한다.
- leader Sentinel이 승격할 replica를 고른다.
- 선택된 replica에
SLAVEOF NO ONE/REPLICAOF NO ONE성격의 승격을 수행한다. - 다른 replica들을 새 master에 붙인다.
- Sentinel의 master 주소 정보가 갱신되고 클라이언트는 새 master를 discovery한다.
이 과정에서 parallel-syncs는 한 번에 몇 개 replica를 새 master에 재동기화할지 정한다. 값이 크면 전체 전환은 빨라질 수 있지만, replica들이 동시에 sync하면서 부하가 커진다. replica가 read traffic을 받고 있다면 재동기화 중 응답 영향도 커질 수 있으므로 보수적으로 1을 쓰는 경우가 많다.
클라이언트 연결 방식
Sentinel 구성을 해놓고 애플리케이션이 여전히 redis://10.0.0.10:6379처럼 master IP를 고정해 쓰면 장애 조치가 끝나도 애플리케이션은 자동으로 복구되지 않는다. Sentinel-aware client는 다음 절차를 따른다.
- 설정된 Sentinel 주소 목록 중 하나에 짧은 timeout으로 연결한다.
SENTINEL get-master-addr-by-name mymaster로 현재 master 주소를 묻는다.- 받은 Redis 주소에 접속한다.
ROLE또는INFO replication으로 정말 master인지 확인한다.- 연결이 끊기면 이전 주소를 재사용하지 말고 Sentinel부터 다시 질의한다.
read scaling을 위해 replica를 사용할 때는 SENTINEL replicas mymaster로 replica 목록을 얻을 수 있다. 다만 replica read는 replication lag를 감수하는 읽기다. 사용자 세션 직후 읽기, write-after-read가 중요한 경로, 잠금 상태 확인처럼 최신성이 중요한 요청은 master로 보내는 편이 안전하다.
Sentinel + persistence 조합의 함정
Redis 공식 복제 문서는 persistence를 끈 master를 자동 재시작하도록 두는 구성을 강하게 경고한다. 위험한 시나리오는 다음과 같다.
- master A는 persistence가 꺼져 있다.
- replica B, C가 A를 복제한다.
- A가 crash 후 빠르게 자동 재시작한다.
- persistence가 없으므로 A는 빈 데이터셋으로 뜬다.
- Sentinel이 장애를 감지하기 전에 B, C가 빈 A를 계속 복제하면 replica 데이터도 지워질 수 있다.
Sentinel이 있어도 이 위험은 사라지지 않는다. 데이터가 중요하다면 master와 replica 모두 persistence 정책을 명확히 정해야 한다. 순수 캐시라서 유실을 허용하는 경우에도, 운영자는 “재시작 후 warm-up 비용”과 “빈 데이터셋이 replica로 전파되는 위험”을 알고 있어야 한다.
실무 구성 체크리스트
| 항목 | 권장 기준 | 이유 |
|---|---|---|
| Sentinel 수 | 최소 3개 | 과반 기반 failover와 Sentinel 자체 가용성 |
| 장애 도메인 | 서로 다른 VM/호스트/AZ | 한 장애가 Sentinel 다수를 동시에 죽이지 않게 함 |
| client | Sentinel-aware client 사용 | master 주소 변경을 자동 추적 |
| timeout | 짧은 Sentinel connect timeout | 장애 Sentinel 때문에 앱 부팅/재연결이 오래 막히지 않게 함 |
| persistence | 데이터 중요도에 맞게 RDB/AOF 설정 | failover와 재시작 시 데이터 안전성 |
parallel-syncs | 보수적으로 1부터 시작 | failover 후 replica 재동기화 부하 제한 |
| monitoring | replication lag, connected replicas, Sentinel 이벤트 | 장애 전조와 failover 결과 확인 |
| drill | 정기 failover 테스트 | 클라이언트, 알림, runbook 검증 |
관측 지표는 최소한 다음을 포함한다.
- master의
connected_slaves - master와 replica의 replication offset 차이
- replica의
master_link_status - full sync 발생 횟수와 시간
- Sentinel
+sdown,+odown,+switch-master이벤트 - 애플리케이션 Redis reconnect/error rate
언제 Sentinel 대신 Cluster를 봐야 하나
Sentinel은 단일 master 그룹의 고가용성을 해결한다. 쓰기는 여전히 한 master로 들어가고, 데이터 샤딩을 제공하지 않는다. 데이터셋이 단일 노드 메모리 한계를 넘거나, write throughput을 여러 master로 나눠야 한다면 다음 장의 Redis Cluster가 더 적합하다.
반대로 데이터 크기는 단일 master에 들어가고, 필요한 것은 자동 failover와 read replica 정도라면 Sentinel이 단순하고 이해하기 쉽다. 운영 복잡도를 줄이고 싶다면 관리형 Redis 서비스의 HA 옵션도 함께 검토할 만하다.
References
- Redis documentation, “Redis Replication”: https://redis.io/docs/latest/operate/oss_and_stack/management/replication/
- Redis documentation, “High availability with Redis Sentinel”: https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/
- Redis documentation, “Redis Sentinel client spec”: https://redis.io/docs/latest/operate/oss_and_stack/reference/sentinel-clients/
- Redis command reference,
ROLE: https://redis.io/docs/latest/commands/role/ - Redis command reference,
WAIT: https://redis.io/docs/latest/commands/wait/