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) 바로 적용 순서
- 캐시 저장 시 TTL 지터 적용
- 미스 발생 시 single flight(한 요청만 원본 조회) 적용
- 다른 요청은 짧게 대기하거나 stale 데이터 반환
- 원본 조회 실패 시 즉시 500 대신 대체 응답 사용
- 핫키 지표를 별도 대시보드로 분리
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 허용 상향 절차 기록
캐시 운영의 목표는 평균 응답시간 개선이 아니라 피크 시간대 생존성입니다. 이 관점으로 바꾸면 스탬피드 재발률이 확실히 내려갑니다.