캐시 스탬피드란 무엇인가
캐시 스탬피드는 캐시에 저장된 데이터가 만료되는 순간, 동일한 데이터를 요청하는 대량의 트래픽이 한꺼번에 원본 서버(DB)로 몰려가는 현상을 말한다. 영어 단어 ‘Stampede’가 ‘동물들이 한꺼번에 우르르 몰려가는 것’을 뜻하는 것처럼, 평소에는 캐시가 막아주던 요청들이 캐시 만료 시점에 한 번에 뒤로 쏟아지는 것이다. 이를 ‘캐시 미스 폭풍(Cache Miss Storm)’ 또는 ‘썬더링 허드(Thundering Herd)’라고도 부른다.
보통 서비스에서는 자주 조회되는 데이터를 캐시에 저장해 DB 부하를 줄인다. 그런데 캐시에는 보통 TTL(Time To Live, 만료 시간)이 설정되어 있는데, 이 TTL이 끝나는 순간 캐시는 비어있는 상태가 된다. 이때 하필 인기 있는 데이터라면 수백, 수천 개의 요청이 동시에 ‘캐시에 없네? DB에서 가져와야지’라고 판단하고 전부 DB로 몰려가게 된다.
왜 이런 일이 발생하는가 (동작 원리)
예를 들어 인기 상품 페이지의 가격 정보를 캐시에 저장하고 TTL을 60초로 설정했다고 가정하자. 60초 동안은 첫 번째 요청만 DB를 조회하고 나머지는 캐시에서 값을 가져가므로 DB는 여유롭다. 하지만 60초가 지나 캐시가 만료되는 정확히 그 순간, 마침 접속해 있던 수천 명의 사용자 요청이 동시에 ‘캐시 미스’를 겪는다. 각 요청은 독립적으로 ‘DB에 값이 없으니 조회해서 다시 캐시에 채워 넣어야지’라고 판단하고, 결과적으로 똑같은 쿼리가 DB에 수천 번 동시에 날아간다.
이는 마치 놀이공원에서 인기 놀이기구가 잠깐 운행을 멈췄다가 다시 열리는 순간, 대기하던 사람들이 입구로 한꺼번에 몰려드는 것과 비슷하다. 평소에는 줄을 서서 순서대로 들어가지만, 문이 열리는 그 찰나에는 모두가 동시에 밀고 들어가려 하는 상황이 벌어지는 것이다. 이 현상이 심해지면 DB 커넥션이 고갈되고, 응답 지연이 발생하며 심한 경우 서비스 전체가 다운될 수도 있다.
실무에서 어떻게 대응하는지
캐시 스탬피드를 막기 위한 대표적인 방법은 다음과 같다.
- Lock(락) 방식: 캐시 미스가 발생하면 하나의 요청만 DB 조회를 수행하도록 락을 걸고, 나머지 요청은 대기하거나 이전 값을 잠시 사용하게 한다.
- 확률적 조기 갱신(Probabilistic Early Expiration): TTL이 끝나기 전에 확률적으로 미리 캐시를 갱신해, 만료 시점이 한 번에 몰리지 않도록 분산시킨다.
- TTL 값에 랜덤성 부여: 모든 캐시의 만료 시간을 동일하게 두지 않고 ’60초 ± 5초’처럼 약간의 오차를 주어 동시 만료를 방지한다.
- Stale-While-Revalidate: 캐시가 만료되어도 오래된 값을 잠시 반환하면서 백그라운드에서 갱신을 진행한다.
이러한 기법들은 Redis, Memcached 등 실제 캐시 시스템을 운영할 때 필수적으로 고려해야 하는 요소다. 단순히 ‘캐시를 쓰면 빠르다’는 개념을 넘어, 캐시가 만료되는 순간의 부하까지 설계 단계에서 고려하는 것이 안정적인 서비스 운영의 핵심이다.