TTL — 시간에 맡긴다

가장 단순하다. 저장할 때 만료를 걸고 지나면 사라진다.

SET product:42 {...} EX 300

바뀌는 빈도가 낮거나 잠깐 낡아도 되는 데이터에 잘 맞는다. 가장 먼저 시도할 방법이고, 이걸로 충분한 경우가 많다.

명시적 삭제 — 바뀔 때 지운다

데이터를 갱신하면서 캐시도 함께 지운다.

productRepository.save(product);
cache.delete("product:" + product.getId());

문제는 대개 파생 캐시에서 생긴다. 상품 하나를 고쳤을 때 product:42만이 아니라 목록 캐시, 카테고리 캐시, 검색 결과 캐시가 모두 낡는다. 새 화면을 추가하면서 캐시를 하나 더 만들었는데 무효화를 빠뜨리는 일이 흔하다.

DB 갱신과 캐시 삭제 사이에 장애가 나면 낡은 값이 남는 것도 감안해야 한다. 그래서 명시적 삭제를 쓰더라도 TTL을 함께 걸어두는 편이 안전하다.

버전 키 — 지우지 않고 무효화한다

키에 버전을 넣고, 무효화가 필요하면 버전을 올린다.

키 :  product:42:v7
갱신:  version:product:42 → 8
조회:  product:42:v8   (없음 → 새로 채운다)

카테고리 버전을 올려 그 카테고리의 모든 캐시를 한 번에 무효화하는 식으로, 묶어서 무효화할 때 특히 강하다.

스탬피드

셋 중 무엇을 쓰든 만나는 문제다. 인기 있는 키가 만료되는 순간 요청 수천 개가 동시에 빈 캐시를 보고 한꺼번에 DB로 몰린다.

정리

  실시간성 구현 난이도 메모리
TTL 낮음 낮음 좋음
명시적 삭제 높음 높음 좋음
버전 키 높음 중간 나쁨

TTL로 시작해서 부족한 지점만 다른 전략으로 보강하는 순서를 권한다. 처음부터 정교하게 만들면 무효화 누락을 찾느라 시간을 더 쓰게 된다.