16강 / 20강
캐시 — 자주 쓰는 것을 손 닿는 곳에
LRU · 히트율 · 그리고 캐시가 만드는 새로운 사고들
상품 상세 페이지 하나를 만드는 데 이런 일이 필요합니다.
- 상품 정보 조회 (DB · 20ms)
- 재고 조회 (DB · 15ms)
- 리뷰 평균 계산 (DB · 80ms)
- 함께 산 상품 계산 (그래프 탐색 · 120ms)
합계 235ms. 초당 100명이 들어오면 서버가 버티지 못합니다.
그런데 잘 보세요. 같은 상품 페이지를 1,000명이 보는데 매번 똑같은 계산을 1,000번 하고 있습니다.
13강에서 배운 그 아이디어가 그대로 필요합니다. 한 번 계산한 건 저장해 두고 다시 쓰자. 이것이 캐시(cache)예요.
히트율이 높을수록 캐시가 잘 작동하고 있다는 뜻입니다.
Python
브라우저에서 실행
문제 — 캐시는 무한하지 않다
위 코드의 캐시는 계속 커집니다. 상품이 3만 개면 3만 개가 다 들어가요. 메모리가 터집니다.
그래서 크기를 정해 두고, 가득 차면 무언가를 버려야 합니다. 무엇을 버릴 것인가 — 이것이 캐시 교체 정책입니다.
| 정책 | 버리는 기준 | 특징 |
|---|---|---|
| LRU | 가장 오래 안 쓴 것 | 가장 널리 쓰임. 최근 쓴 건 또 쓸 거라는 가정. |
| LFU | 가장 적게 쓴 것 | 인기 상품에 유리. 옛날 인기가 오래 남는 단점. |
| FIFO | 가장 먼저 들어온 것 | 단순하지만 성능이 나쁨. |
| TTL | 정해진 시간이 지난 것 | 신선도 보장. 다른 정책과 함께 씀. |
OrderedDict 하나로 LRU가 완성됩니다. 실행해서 무엇이 버려지는지 보세요.
Python
브라우저에서 실행
🎮 LRU 캐시 시뮬레이터
캐시 크기를 바꿔 가며 히트율이 어떻게 변하는지 보세요. 접속 패턴도 고를 수 있습니다 — 인기 상품 집중형과 고르게 분산형에서 같은 캐시 크기라도 히트율이 완전히 달라집니다.
무엇을 캐시하고 무엇을 하지 말아야 할까
| 데이터 | 캐시? | 이유 |
|---|---|---|
| 상품 이름 · 설명 · 이미지 | ✅ 길게 (시간 단위) | 거의 안 바뀜 |
| 리뷰 평균 · 추천 목록 | ✅ 중간 (분 단위) | 계산이 비싸고, 조금 늦어도 괜찮음 |
| 가격 | ⚠️ 짧게 + 변경 시 무효화 | 틀리면 금전 사고 |
| 재고 수량 | 🚫 거의 안 함 | 틀리면 없는 물건을 판매 |
| 장바구니 · 결제 진행 | 🚫 절대 안 됨 | 사람마다 다르고 실시간이어야 함 |
원칙은 하나예요. "조금 낡아도 괜찮은 것"만 캐시한다.
lru_cache 의 cache_info() 로 히트율을 바로 볼 수 있습니다.
Python
브라우저에서 실행
🤔 확인 문제
캐시 히트율이 95%라는 것은 무슨 뜻일까요?
해설 100번 중 95번은 비싼 계산을 건너뛰었다는 뜻입니다. 히트율은 캐시 운영의 가장 중요한 지표예요.
🤔 확인 문제
LRU 캐시가 가득 찼을 때 버리는 항목은?
해설 Least Recently Used — 가장 최근에 안 쓴 것입니다. '최근에 쓴 건 또 쓸 것'이라는 가정에 기대죠. 가장 적게 쓴 것을 버리는 건 LFU예요.
🤔 확인 문제
인기 상품의 캐시가 만료되는 순간 수천 개의 요청이 동시에 DB로 몰리는 현상은?
해설 캐시 스탬피드(cache stampede)입니다. 만료 시각을 흩뜨리거나, 첫 요청만 계산하고 나머지는 기다리게 하는 방식으로 막습니다.