Engineering

Redis 캐시 스탬피드 방지: 트래픽 급증에도 DB를 지키는 운영 플레이북

Mike발행일 2026년 2월 27일수정일 2026년 2월 27일읽는 시간 약 1

💡 Key Takeaways

  • 핫키는 짧은 TTL보다 TTL 분산과 단일 비행이 효과적입니다.
  • 캐시 미스 실패를 500으로 바로 내보내면 스탬피드가 더 커집니다.
  • stale 허용 정책을 두면 피크 시간대 품질을 안정적으로 유지할 수 있습니다.
  • 핫키 지표와 장애 런북을 고정해야 야간 대응이 빨라집니다.

Redis 캐시 스탬피드 방지: 트래픽 급증에도 DB를 지키는 운영 플레이북

캐시는 평소에 잘 동작해서 방심하기 쉽습니다. 문제는 이벤트 트래픽이 몰릴 때입니다. 같은 키가 동시에 만료되면 요청이 한꺼번에 DB로 쏠리고, 그 순간부터 전체 응답이 흔들립니다. 이게 캐시 스탬피드입니다. 경험상 Redis 용량을 늘리는 것만으로는 해결되지 않았고, 만료/재생성 정책을 같이 설계해야 효과가 있었습니다.

1) 가장 먼저 할 일: 핫키 분리

모든 키를 같은 정책으로 운영하면 실패합니다. 최소한 아래 2가지는 분리하세요.

  • 핫키: 요청량 상위 키 (예: 상품 목록, 홈 피드)
  • 콜드키: 요청량 낮은 일반 키

핫키에는 TTL 지터(랜덤 분산)를 기본 적용해야 합니다. 예: 300초 기준이라면 240~360초 범위로 분산.

2) 바로 적용 순서

  1. 캐시 저장 시 TTL 지터 적용
  2. 미스 발생 시 single flight(한 요청만 원본 조회) 적용
  3. 다른 요청은 짧게 대기하거나 stale 데이터 반환
  4. 원본 조회 실패 시 즉시 500 대신 대체 응답 사용
  5. 핫키 지표를 별도 대시보드로 분리

3) 최소 구현 예시

const lock = await redis.set(lockKey, '1', { NX: true, EX: 5 })
if (lock) {
  const fresh = await loadFromDb()
  await redis.set(dataKey, JSON.stringify(fresh), { EX: jitter(300) })
  return fresh
}

const stale = await redis.get(dataKey)
if (stale) return JSON.parse(stale)
return fallbackResponse()

핵심은 "락 실패 = 장애"로 처리하지 않는 것입니다. 락 실패는 스탬피드 방지 흐름의 일부입니다.

4) 운영 체크리스트

  • cache_hit_rate만 보지 말고 lock_wait_ms, origin_qps, hotkey_top_n도 본다
  • 배포 전 신규 키 네이밍 규칙 준수 확인
  • 피크 시간 전 TTL 분포가 한쪽으로 몰리지 않았는지 확인
  • 장애 런북에 임시 TTL 연장 절차와 stale 허용 상향 절차 기록

캐시 운영의 목표는 평균 응답시간 개선이 아니라 피크 시간대 생존성입니다. 이 관점으로 바꾸면 스탬피드 재발률이 확실히 내려갑니다.

함께 읽으면 좋은 글

Engineering

Next.js 인증 리다이렉트 루프 방지 플레이북: 로그인 UX와 보안을 동시에 지키는 운영 설계

2026-03-03
Engineering

Next.js 서버 액션 장애 복구 플레이북: 실패를 사용자 이탈로 번지지 않게 막는 실무 설계

2026-03-01

본문 작성/검수 원칙은 편집 원칙에서 확인할 수 있습니다.

← 목록으로 돌아가기