LabHub

Redis 와 캐싱 · 캐시가 왜 어려운가 · 이론

복사본은 원본이 바뀌는 순간 낡는다

LabHub 에서 이어서 보기

한 줄 요약

캐시 전략은 스테일과 미스 사이의 줄타기다. 정답은 없고 데이터의 성격에 맞는 균형점만 있다.

왜 이게 필요했나

캐시가 잘 작동하는 이유는 두 가지 성질 덕분입니다. 시간 지역성 — 방금 쓴 데이터는 곧 또 쓰일 가능성이 높다. 공간 지역성 — 어떤 데이터를 쓰면 그 근처 데이터도 곧 쓰일 가능성이 높다.

문제는 캐시가 원본의 복사본이라는 데서 나옵니다. 복사본은 원본이 바뀌는 순간 낡습니다. 여기서 두 가지 나쁜 상황을 구분해야 합니다. 스테일은 캐시가 원본보다 오래된 값을 들고 있는 것이고, 사용자가 틀린 값을 봅니다. 미스는 캐시에 값이 없어 원본까지 다녀와야 하는 것이고, 느립니다.

스테일을 줄이려 자주 버리면 미스가 늘고, 미스를 줄이려 오래 보관하면 스테일이 늘어납니다. 이 줄타기가 캐시의 모든 어려움의 근원입니다.

어떻게 동작하나

가장 단순한 무효화는 TTL 입니다. 각 항목에 수명을 붙이고 지나면 버립니다. 매력은 단순함과 예측 가능성입니다 — 무효화 로직을 따로 짤 필요가 없고, 최악의 경우에도 스테일은 TTL 을 넘지 않습니다. 그래서 잠깐 낡아도 괜찮은 데이터에 잘 맞습니다. 뉴스 목록, 인기 게시물, 환율. 반대로 계좌 잔액 같은 것은 TTL 만으로 부족하고 명시적 무효화가 필요합니다.

명시적 무효화에는 두 갈래가 있습니다. 이벤트 기반은 원본이 바뀌면 관련 캐시를 즉시 지웁니다. 최신성은 좋지만 의존성 추적이 어렵습니다 — "상품 42"는 상품 상세 캐시에도, 카테고리 목록 캐시에도, 검색 결과 캐시에도 있을 수 있습니다. 놓친 의존성 하나가 조용한 스테일 버그가 됩니다.

버전 키는 훨씬 견고한 실용적 기법입니다. 키 자체에 버전을 심어 무효화를 삭제 대신 이동으로 처리합니다. user:42:v7:profile 을 쓰다가 데이터가 바뀌면 버전을 v8 로 올립니다. v7 키는 아무도 찾지 않으니 TTL 로 자연히 정리됩니다. 삭제를 직접 하지 않아도 되고, 무효화와 재조회가 엇갈리는 경쟁 조건에도 강합니다. 옛 키와 새 키가 물리적으로 다르기 때문입니다.

현장에서 만나는 모습

무효화가 어려운 진짜 이유는 셋입니다. 첫째, 분산 — 캐시는 여러 서버, 여러 계층에 흩어져 있어 원자적으로 무효화하는 것이 분산 합의 문제가 됩니다. 둘째, 경쟁 조건 — 캐시를 지우는 순간과 다른 요청이 옛 값을 다시 읽어 넣는 순간이 엇갈리면 방금 지운 값이 되살아납니다. 셋째, 의존성의 복잡성.

그래서 실무는 완벽한 무효화를 포기하고 "얼마나 오래 스테일을 견딜 수 있는가"를 정해 TTL 과 명시적 무효화를 섞습니다.

다음 확인에서 볼 것

먼저 퀴즈에서 스테일과 미스의 거래 관계, TTL 이 허용되는 데이터 조건을 확인합니다. 다음 모듈부터 Redis 자료구조를 하나씩 만져 보고, 그다음 랭킹과 캐시 패턴과 스탬피드 방어를 각각 실습합니다.