아키텍처를 설계하다 보면 SPOF(Single Point Of Failure) 라는 개념을 반드시 마주치게 된다.
예를 들어 API Gateway가 파드 1개로만 운영된다면, 이것 하나가 죽었을 때 뒤에 있는 모든 서비스가 아무리 멀쩡해도 전체 서비스가 다운된다.
SPOF를 없애는 방법은 결국 단일 파드/인스턴스를 복제하는 것이다.
API Gateway 스케일링과 인가
우리 프로젝트는 모든 요청이 API Gateway를 통과하는 구조이다.
그래서 API Gateway가 단일 파드면 SPOF이므로 당연히 스케일링 대상이다.
그런데 여기서 한 가지 의문이 생겼다. -> JWT 검증, 즉 인가를 담당하는 모듈을 스케일링해도 되는가?
클쌤과 오랜 시간 얘기해보고 결론부터 말하면 가능하다. 이유는 API Gateway가 상태를 들고 있지 않기 때문이다.
현재 우리 프로젝트에서 API Gateway의 인가 흐름은 다음과 같다.
JWT 검증 → Redis에서 토큰 조회 → 헤더에 사용자 정보 추가 → 라우팅
JWT 검증 로직은 stateless하다
토큰 저장소는 외부 Redis에 있다
리모트 캐시 서버를 사용하기 때문에 파드가 몇 개든 항상 동일한 결과가 나온다. (참고로 로컬 메모리에 들고 있었다면 Sticky Session 문제가 발생한다.)
// 스티키 세션 문제
API Gateway Pod A → 세션 저장 (로컬 메모리)
API Gateway Pod B → 세션 없음
→ Pod B로 라우팅되면 인증 실패
우리는 Redis로 상태를 외부화한 덕분에 API Gateway를 자유롭게 스케일링할 수 있다.
그러면 Redis가 죽으면 어떻게 되나요
API Gateway가 Redis에 의존하고 있다는 말은 곧 Redis가 SPOF가 될 수 있다는 뜻이다.
Redis가 단일 파드로 다운되면 다음과 같은 연쇄 흐름이 발생한다.
0초 : Redis 다운
1초 : 모든 요청에서 Redis 조회 실패
→ 서킷 브레이커 동작
→ User Service로 토큰 검증 폴백
10초 : User Service CPU 급증 → HPA 감지
40초 : HPA가 파드 복제 결정
60~90초: 새 파드 뜨는 중 (이미지 pull → 컨테이너 시작 → 헬스체크)
→ 이 1~90초 사이에 기존 User Service 파드가 과부하로 다운될 수 있다
HPA(오토스케일링)는 사후 대응이기 때문에 파드가 뜨는 시간 동안 기존 파드가 먼저 죽을 수 있다. 그래서 결국 Redis 자체를 죽지 않게 만드는 것이 근본 해결책이다.
Redis Sentinel : Master + Replica 구성, Master 장애 시 Replica가 자동으로 Master로 승격
Redis Cluster : 데이터를 여러 노드에 샤딩하여 분산 저장, 일부 노드 장애에도 서비스 지속 가능
MSA에서 Replica가 필요한 컴포넌트
Redis 하나를 고민하다 보니 결국 전체 아키텍처에 대한 흐름을 생각하게 되었다..
어느 한 계층이라도 단일 파드/인스턴스면 그게 SPOF가 된다.
그래서 우리 잡아클래스 기준으로 정리하면 다음과 같다.
Replica만으로는 2% 부족할때 : 폴백 전략
Replica 구성은 "죽지 않게 만드는 것"이다. 아무리 잘 설계해도 장애는 발생한다고 반드시 가정해야한다.
그래서 "죽었을 때 어떻게 할 것인가" 에 대한 전략도 반드시 함께 설계해야 한다.
Kafka 장애
Outbox 패턴으로 메시지 유실 방지
Redis 장애
서킷 브레이커로 User Service 폴백
DB 장애
Replica로 Read 유지, Write 장애 허용
ES 장애
DB 검색 폴백 또는 503 처리
우리 프로젝트에서 아웃박스 패턴을 도입한 이유도 Kafka가 SPOF가 되지 않도록, Kafka가 죽어도 메시지가 유실되지 않는 구조를 만들기 위함이었다.
결론
Replica로 죽지 않게 만드는 것 + 죽었을 때 어떻게 처리 할지 (서킷 브레이커 / 폴백) -> 이 두가지가 MSA의 고가용성 설계의 핵심이다!