Redis로 Cache-Aside 패턴을 쓰고 있는데 이상한 현상이 있어서 질문 올립니다. 평소엔 캐시가 잘 먹혀서 DB 부하가 낮은데, 조회수 제일 높은 인기 키의 TTL이 딱 만료되는 그 순간에 요청들이 동시에 캐시 미스가 나면서 죄다 DB로 몰려버립니다. 그 찰나에 DB 커넥션이 확 튀고 응답이 밀려요. 검색해보니 cache stampede 또는 thundering herd라고 부르더라고요.


원인은 이해가 됩니다. 핫키 하나가 만료되면 그걸 보던 수많은 요청이 전부 동시에 원본을 다시 읽으러 가니까요.


val = redis.get(key);
if (val == null) { // 여기에 동시에 몰림
val = db.query(...); // 다 같이 DB로
redis.set(key, val, ttl);
}
return val;


대응책으로 세 가지를 봤는데 어느 걸 실무에서 쓰시는지 궁금합니다. 하나는 분산 락을 걸어서 딱 한 요청만 DB에서 재적재하고 나머지는 기다리게 하는 것, 두 번째는 TTL에 지터를 줘서 만료 시각을 랜덤하게 흩뿌려 동시 만료를 막는 것, 세 번째는 stale-while-revalidate처럼 만료돼도 일단 옛 값을 내주면서 백그라운드로 갱신하는 것. 트래픽 성격에 따라 다를 것 같은데 조합해서 쓰기도 하나요?