애플리케이션이 캐시를 직접 관리하는 전략. 캐시를 "옆에 두고(aside)" 필요할 때만 들여다본다는 뜻이다. Look-Aside, Lazy Loading이라고도 한다.
읽기 흐름
다이어그램 로딩 중…
쓰기 흐름 — 갱신이 아니라 삭제
@Transactional
public void updatePrice(Long id, int price) {
productRepository.updatePrice(id, price); // ① DB 갱신
cache.delete("product:" + id); // ② 캐시 삭제
}
왜 갱신하지 않고 지우는가 — 동시 요청에서 순서가 엇갈릴 수 있기 때문이다.
T1: DB에 100 쓰기
T2: DB에 200 쓰기
T2: 캐시에 200 쓰기
T1: 캐시에 100 쓰기 ← 캐시에 낡은 값 100이 남는다
삭제는 이런 역전이 생기지 않는다. 다음 읽기가 DB에서 최신값을 가져오기 때문이다.
순서도 중요하다 — DB 먼저, 캐시 나중
❌ 캐시 삭제 → DB 갱신
- 삭제 직후 다른 요청이 읽어서 옛 DB 값을 캐시에 채움 → 낡은 값 고착
✅ DB 갱신 → 캐시 삭제
- 틈이 있어도 다음 읽기가 새 값을 채운다
✅도 완벽하진 않다(삭제 직전에 읽은 요청이 늦게 캐시를 채우는 경우). 그래서
짧은 TTL을 안전망으로 함께 둔다.
장점과 대가
| 장점 | 실제 읽히는 것만 캐시에 올라감(메모리 효율). 캐시가 죽어도 DB로 서비스 계속 |
| 단점 | 첫 요청은 항상 미스(cold start). DB 갱신과 캐시 삭제 사이 짧은 불일치 |
예열(cache warming)
배포 직후엔 캐시가 비어 있어 트래픽이 전부 DB로 간다. 인기 키를 미리 채워 두거나, 트래픽을 점진적으로 올려 붕괴를 막는다.