이 글에서는 Redis를 안정적으로 적용하기 위한 구성 방식, 특히 Sentinel과 HAProxy를 활용한 고가용성 아키텍처에 대해 단계적으로 알아보려 합니다.
들어가기에 앞서, HAProxy가 필요한 이유부터 차근차근 살펴보겠습니다.
1. 배경 지식
1-1. OSI 7 Layer

1-2. Redis란?
인메모리 기반의 고속 Key-Value 저장소
(다양한 자료구조를 지원하는 NoSQL DB)
1-3. HAProxy vs Nginx 비교
개인적으로 Nginx와 HAProxy의 차이가 궁금해서 찾아보았습니다. 차이점은 아래와 같이 HAProxy와 Nginx 각각이 주로(강점) 역할을 수행하는 곳이 L4, L7로 서로 달랐습니다.


1-4. HAProxy란?
먼저, 간단하게 HAProxy는 부하 분산(Load Balancer) 및 프록시 서버입니다.
역할
1. TCP 및 HTTP 기반 트래픽을 중계 가능
2. 헬스 체크, 장애 감지, 페일오버 처리 가능
3. Redis처럼 TCP 기반 프로토콜에서도 사용 가능
그럼 Redis에는 Sentinel과 Cluster 두가지로 구성할 수 있는데 두개의 차이점을 알아보겠습니다.
이번에는 Redis의 고가용성/분산 처리를 위해 구성 방식을 선택하기 위해 Sentinel 방식과 Cluster 방식 각각의 목적과 사용환경을 알아보겠습니다.
Redis Sentinel vs Redis Cluster
| Redis Sentinel | Redis Cluster | |
| 목적 | 작은 서비스(간단하고 안정적인 처리) 고가용성, Master 장애 감지 & 자동 Failover 수행 |
큰 서비스(분산 저장 & 고성능 처리) 수평 확장 + 고가용성 |
| 구성 복잡도 | 낮음 | 높음 |
| 수평 확장 | 불가능 | 가능 |
| 데이터 크기 | 소규모 서비스 | 대규모 분산 서비스 |
이러한 Redis Sentinel과 Redis Cluster에는 위와 같은 차이가 있다. 저의 프로젝트는 규모가 크지 않음으로 Redis Sentienl로 진행할 예정입니다.
Redis에서 HAProxy는 간단하게 아래와 같은 역할을 한다.

1. Redis Sentinel이 Master를 감시하고 장애 감지
2. Sentinel이 Master를 교체하면 → HAProxy가 감지
3. HAProxy는 새로운 Master로 트래픽 라우팅 전환
4. 클라이언트는 항상 HAProxy만 바라보므로 연결 끊김 없이 처리
2. Redis 기본 구조 이해

본격적인 고가용성 구성을 살펴보기 전에, Redis 기본 구조를 간단히 짚고 넘어가겠습니다.
Redis는 단일 프로세스로 동작하는 인메모리 Key-Value 저장소 입니다. 모든 데이터는 메모리에 저장되며, 빠른 응답 속도를 장점으로 갖고 있습니다.
기본적으로는 하나의 Redis 인스턴스가 Read/Write를 담당하여 별다른 구조 없이 작동합니다.
하지만, 이런 구조는 단일 장애 지점(SPOF, Single Point of Failure)이 되기 때문에 운영 환경에서는 문제가 되는 지점일 수 있습니다.
이를 해결하기 위해 이번에는 Redis Replication 구조를 알아보겠습니다.
3. Redis Replication : Master-Slave 구조로 확장
Replication 구조에서는 하나의 Master 서버가 모든 Read/Write를 처리하고 하나 이상의 Slave 서버가 Master의 데이터를 실시간으로 복제합니다.
- Master: 클라이언트의 write, read 요청 모두 처리
- Slave: Master의 데이터를 실시간으로 복제하고 Read요청만 가능

위 그림과 같이 하나의 Master가 여러 Slave와 연결된 구조로 만들 수 있으며 이를 통해 읽기 작업은 부하 분산을 시킬 수 있습니다.
장점
Write(Master 전용) → 일관성 보장, 데이터 충돌 방지
Read(Slave 분산) → 부하 분산 + 성능 향상
하지만, 이 구조는 Master에 장애 발생 시 Redis 기본 구조와 마찬가지로 SPOF문제가 있습니다.
이를 해결하기 위해 다음 단계인 Sentinel 구성이 필요합니다.
4. Redis Sentinel : 장애 감지 & 자동 Failover
Replication 구조는 읽기 부하를 줄여주지만, 여전히 Master에 장애 발생시 수동으로 해결해야만 한다는 한계가 있습니다.
4-1. Sentinel의 역할
1. Master/Slave Redis 인스턴스 모니터링
2. 장애 감지(Failure Detection)
3. 자동 Failover(Slave를 Master로 승격)
4. 클라이언트에게 새로운 Master 정보 전달
아래 그림처럼 Sentinel은 각 Redis 노드(Master+Slave)를 모니터링하다 Master에 문제가 생겼을 때 투표를 통해 Slave 중 하나를 Master로 승격시킵니다.

4-2. Sentinel이 3대인 이유
- 장애 판단 정확도 향상: 네트워크 문제 or 어떤 결함의 문제가 발생하였을 때 Sentinel 자체의 문제일 가능성을 배제하지 않기위해 여러대를 둡니다.
- 다수결 투표(Quorum): Redis Sentinel은 'SDown&ODown' 개념 때문에 홀수개로 두는게 좋습니다.
(ex. 투표시 짝수일 경우 5:5일 경우 결론이 나지 않기 때문입니다.)
4-3. SDown vs ODown
- SDown(Subjective Down, 주관적인 다운상태)
Sentinel이 사실 정상작동중인데 일시적인 네트워크 오류로 인해 주관적으로 다운상태라고 하는 것
- ODown(Objective Down, 객관적인 다운상태)
여러 Sentinel이 다수결로 해당 Master를 SDown상태라고 판단한 상태
4-4. Sentinel의 Slave 승격 과정
Q: Sentinel이 failover하기위한 것이라면 master정보 뿐만아니라 slave 정보도 있어야 하지 않을까요?
A: 그래서 아래 명령어를 통해 Sentinel이 Master에 접속하여 slave들의 정보를 조회합니다.
INFO replication
이를 위해 quorum 값을 다수결 이상으로 잘 설정하여 failover 설정을 하게 됩니다.
또한, 몇 초동안 master로의 연결이 실패했을 때 SDown으로 간주할 것인지를 설정합니다.
(참고)
Sentinel은 내부적으로 Redis의 Pub/Sub 기능을 사용하여 정보를 주고 받습니다.(_sentinel_:hello라는 채널)
이를 통해 conf에서 따로 설정없이 잘 통신합니다.
문제점!
Client에서 write를 하기 위해 7000번을 사용하고, read를 하기 위해 slave(7001~3)을 사용하고 있습니다.
즉, Master가 종료되고, sentinel에 의해 Slave(7001)이 master가 될 것입니다.
하지만, Client는 여전히 7000이 Master라고 생각할 것입니다.(7000번이 죽었다라는 것을 알더라도 현재 Master는 7000이라는 것을 알 수 없습니다.)
물론 Client코드에서 해결할 순 있겠지만 굉장히 '비.효.율'적입니다. 이를 위해 HAProxy라는 것을 사용하면 해결할 수 있습니다.
4-5. Redis Sentinel 실습
(1) 초기 세팅이 잘 되었는지 확인


(2) Sentinel 내부 동작과정 확인(logs)

위 이미지(Sentinel 로그)를 통해 Sentinel이 내부적으로 어떻게 동작하는지 확인할 수 있습니다.
위와 같이 '장애 감지 -> 투표 -> 새 master 승격' 과정을 통해 아래 이미지와 같이 Read는 잘 동작하는 것을 확인 할 수 있습니다.
(3) 새 master 승격 후 동작 확인

(4) Sentinel 내부 로그 확인

Sentinel이 failover를 잘 수행하였지만, 클라이언트는 7000(redis-master)를 사용하려는 문제 발생
(5) redis-master 재실행 및 작동 테스트

그래서 Redis-Master를 재실행하였지만, 클라이언트는 더 이상 7000포트를 신뢰할 수 없습니다.
(이유: 현재 master는 slave1이였던 7001포트를 master로 인식하기 때문입니다.)
5. HAProxy를 이용한 Switching
5-1. 구성 요소 및 역할
| 구성 요소 | 역할 |
| HAProxy | 클라이언트 진입점, read/write 요청을 Redis 서버로 라우팅 |
| redis-master | 유일한 쓰기 대상(write only) |
| redis-slave1~3 | read only, Master와 실시간 동기화 |
| Sentinel 1~3 | Master 감시 + 장애 발생 시 자동 failover 수행 |
| Stats UI | http://localhost:8404/stats에서 상태 확인 |
간략한 장애 발생시 복구 과정
Master 장애 시 → Sentinel이 새 Master 승격 → HAProxy가 전환 필요
5-2. 장점
1. 성능 향상: 읽기 요청을 여러 Slave로 분산하여 트래픽 부하 분산
2. 단순한 연결: 단일 엔드포인트 사용(클라리언트는 하나의 엔드포인트만 바라봄)
3. 모니터링: 'http://localhost:8404/stats'로 HAProxy 상태 및 라우팅 현황 확인
4. 자동 복구: 장애 Redis 서버 자동 제외, 복구 시 재등록
5. 고가용성: Sentinel + HAProxy 조합으로 장애 시에도 서비스 지속 가능
5-3. Sentinel & HAProxy의 책임
| 구성 요소 | 주요 역할 |
| Sentinel | Master 장애 감지 -> 새로운 Master 자동 승격 |
| HAProxy | 클라이언트의 Redis 요청을 현재 Master에 자동 라우팅 |
Q: Sentinel만으로 고가용성인가??
A: Sentinel만 있어도 Redis 자체는 고가용성입니다.(Master 죽으면 Slave가 자동 승격)
A: HAProxy가 별도로 Master 주소를 알고 라우팅한다면 클라이언트는 변화 없이 연결 유지 가능
5-4. Redis HAProxy 실습
(1) 초기 작동 테스트 및 상태 확인


(2) redis-master 중지 및 상태 확인


(3) redis-slave1이 잘 승격되었는가 확인

(4) redis-master 재실행 후


6. 마무리
이번 글에서는 Redis를 안정적으로 운영하기 위한 고가용성 아키텍처를 단계적으로 살펴보았습니다.
단순한 단일 Redis 인스턴스 구조에서 출발해, Replication → Sentinel → HAProxy로 점진적으로 확장해나가며 시스템의 복원력과 안정성을 강화하는 과정을 다뤘습니다.
Redis는 단순하면서도 강력한 성능을 가진 인메모리 DB입니다. 하지만, 실 서비스 환경에서는 언제든 장애가 발생할 수 있어 항상 그에 대한 대비가 필요합니다. 따라서 항상 어떤 기술을 쓸 때마다 왜 이 기술을 선택하였고, 어떻게 구성되고 어떤 방식으로 동작하는지 체계적으로 이해하는 것이 중요하다고 생각합니다. 이번 경험을 통해 인프라 관점에서 시스템을 바라보는 시야를 넓힐 수 있었습니다.
Source Code
- Redis-Sentienl 소스코드
- Redis-HAProxy 소스코드
Reference
'Spring' 카테고리의 다른 글
| JVM 메모리 누수 처리 방법 (1) | 2025.06.28 |
|---|---|
| 01. 스프링 프레임워크란? (0) | 2023.06.25 |