제목
- *Node.js에서 Redis 연결의 신뢰성 확보: 지연 로딩, 재시도 로직 및 서킷 커 🦆**
분야
- *프로그래밍/소프트웨어 개발**
대상자
- Node.js 및 Redis를 사용하는 개발자
- 생산 환경에서 Redis 연결의 안정성을 요구하는 개발자
- 요약된 기술적 구현 패턴을 활용해 시스템 신뢰성을 높이고 싶은 개발자
핵심 요약
- *_ioredis와 opossum을 활용한 Redis 연결 안정화 전략_**
- 지연 로딩 (Lazy Loading): Redis 클라이언트는 요청 시 생성하여 불필요한 연결을 방지 (
rawRedis()
싱글톤 패턴) - 재시도 로직 (Retry Logic):
retryStrategy
를 통해 최대 4회 재시도 후 연결 실패 로그 기록 - 서킷 커 (Circuit Breaker):
opossum
를 사용해 Redis 장애 시 요청 차단 및 복구 시도 기능 구현 - _maxRetriesPerRequest: 1_로 무한 재시도 방지, _errorThresholdPercentage: 50_로 장애 판단 기준 정의
섹션별 세부 요약
1. 초기 접근 방식 및 문제점
- 전역 변수로 Redis 클라이언트 초기화:
const redis = new Redis();
로 시작 시 연결 문제 발생 - 문제 요약:
- Redis 서버가 준비되지 않은 경우 시작 시 연결 오류
- 무한 재시도로 인한 리소스 과다 사용
- 장애 시 대체 전략 부재
2. 지연 로딩 및 싱글톤 패턴 적용
- 싱글톤 클라이언트 생성:
rawRedis()
함수로 연결 생성 시점 지연 - 코드 구조:
```typescript
const rawRedis: () => Redis = (() => {
let client: Redis | null = null;
return () => {
if (!client) {
client = new Redis({ retryStrategy, maxRetriesPerRequest: 1 });
...
}
};
})();
```
- 이점: 메모리 누수 방지 및 필요 시점에만 연결 생성
3. 재시도 로직 및 서킷 브레이커 구현
- 재시도 전략 정의:
```typescript
retryStrategy(times) {
if (times > 4) return null; // 최대 4회 재시도 후 중단
const delay = Math.min(times * 200, 2000);
return delay;
}
```
- 서킷 브레이커 옵션:
```typescript
const breakerOptions = {
timeout: 500, // 500ms 초과 시 실패로 간주
errorThresholdPercentage: 50, // 50% 이상 실패 시 서킷 열기
resetTimeout: 30_000, // 30초 후 반복 시도 (반열 상태)
};
```
- 서킷 상태 로깅:
- open
: 서킷 열림 (대체 로직 실행)
- halfOpen
: 반열 상태 (부분 재시도)
- close
: 서킷 닫힘 (정상 연결)
4. 라우터에서의 사용 사례
- Redis 명령어 호출 방식:
```typescript
const count = await redis.fire("incr", "global:counter");
if (count === null) {
return res.send({ counter: "unavailable" });
}
```
- 장점:
- Redis 장애 시 사용자 요청 무시
- 서킷 브레이커의 두 번째 방어 계층으로 시스템 안정성 강화
결론
- *_Redis를 단점 없는 서비스 레이어로 전환_**
- 지연 로딩, 재시도 로직, 서킷 브레이커 세 가지 전략을 통해 Redis 연결의 안정성과 복구 능력 향상
- 실무 팁:
- _errorThresholdPercentage_는 환경에 따라 조정 필요 (예: 고가용성 시 30%로 설정)
- _resetTimeout_은 네트워크 지연을 고려해 10~60초 범위 권장
- _maxRetriesPerRequest_는 명령어 복잡도에 따라 1~3회 조정 가능
- 결과: Redis 장애 시 애플리케이션 정체 없이 복구 및 사용자 경험 보장 가능