과거 데이터의 저주: 캐시 무효화와 갱신 전략
원본 데이터가 변경되었을 때 Redis의 캐시 데이터를 언제 어떻게 갱신하거나 무효화할지 결정하는 전략을 익힙니다.
이전 회차에서 TTL을 통해 데이터가 언젠가는 사라지게 만들었습니다. 하지만 TTL이 끝나기 전에 메인 데이터베이스의 원본 내용이 수정된다면 어떻게 될까요? 사용자는 여전히 과거의 데이터(캐시)를 보게 됩니다. 이번 시간에는 원본이 변했을 때 캐시를 어떻게 처리해야 하는지, '캐시 무효화'의 개념을 살펴봅니다.
캐시 불일치가 불러오는 혼란
사용자가 자신의 프로필 이름을 '김개발'에서 '김운영'으로 수정했다고 가정해 봅시다. 원본 데이터베이스(PostgreSQL)는 즉시 수정되었습니다. 하지만 프로필 정보가 Redis에 캐시되어 있고 TTL이 아직 10분이나 남았다면, 사용자는 10분 동안 변경 전 이름인 '김개발'을 계속 보게 됩니다.
사용자의 불만과 버그 신고
자신이 방금 바꾼 정보가 화면에 반영되지 않으면, 사용자는 버그라고 생각하고 새로고침을 연타하거나 고객센터에 문의를 남기게 됩니다. 이러한 데이터 불일치(Data Inconsistency) 현상은 서비스의 신뢰도를 크게 떨어뜨리는 원인이 됩니다.
캐시 사용 시 흔한 실수
오해 또는 실수
원본 DB만 수정하고 끝낸다
바로잡기
데이터 수정 시 관련된 Redis 캐시도 함께 지우거나 수정해야 합니다.
오해 또는 실수
모든 데이터를 실시간 반영하려 한다
바로잡기
별점 통계처럼 약간 과거 데이터라도 상관없는 것은 그냥 TTL만 믿고 놔두는 것이 성능에 좋습니다.
캐시 무효화 (Cache Invalidation)
이 문제를 해결하기 위해 캐시 무효화(Cache Invalidation) 기법을 사용합니다. 무효화란 원본 데이터에 변경(생성, 수정, 삭제)이 일어났을 때, 기존에 존재하던 Redis 캐시 데이터를 강제로 지워버리는 것을 말합니다.
왜 캐시를 수정하지 않고 지울까?
캐시를 직접 새로운 값으로 덮어쓰는(Update) 방법도 있지만, 대부분의 실무에서는 그냥 캐시를 지우는(Delete) 방식을 선호합니다. 데이터 구조가 복잡할 경우 캐시를 수정하는 연산 자체가 무거울 수 있고, 동시성 문제(여러 명이 동시에 수정할 때 데이터가 꼬이는 현상)가 발생할 수 있기 때문입니다. 캐시를 지워버리면, 다음번 조회 요청이 들어왔을 때 빈 공간을 확인하고 데이터베이스에서 깨끗한 최신 데이터를 다시 읽어와 채워넣게 됩니다.
캐시 무효화(삭제) vs 캐시 갱신(수정)
| 비교 항목 | 캐시 무효화 (지우기) | 캐시 갱신 (덮어쓰기) |
|---|---|---|
| 장점 | 구현이 아주 단순하고 데이터 꼬임 현상이 적음 | 다음 사용자가 캐시 미스를 겪지 않아 첫 응답이 빠름 |
| 단점 | 캐시가 지워진 직후의 첫 요청은 메인 DB를 조회하므로 느림 | 동시 다발적인 수정 시 데이터 정합성을 맞추기 매우 복잡함 |
| 실무 추천도 | ⭐⭐⭐⭐⭐ (권장) | ⭐⭐ (특수 상황에서만 사용) |
실무에서 캐시를 지우는 타이밍
그렇다면 캐시는 언제 지워야 할까요? 정답은 간단합니다. 원본 데이터베이스에 변화를 주는 이벤트(API 요청)가 성공적으로 끝난 직후입니다.
변경 API와 함께 묶기
사용자 정보를 업데이트하는 `PUT /users/profile` API가 호출되면, 내부 로직은 먼저 PostgreSQL의 데이터를 업데이트합니다. 성공했다면 즉시 해당 사용자의 정보를 담고 있는 Redis 키를 `DEL` 명령어로 삭제합니다.
프로필 수정 시 캐시 무효화 흐름
// 1. 메인 데이터베이스(PostgreSQL)의 사용자 정보를 업데이트합니다.
await db.users.update({ name: '김운영' }, { where: { id: userId } });
// 2. 변경이 성공했다면 관련된 Redis 캐시를 즉각 삭제(무효화)합니다.
await redisClient.del(`user:profile:${userId}`);개념 퀴즈
퀴즈 답을 맞춰야 학습 완료가 됩니다.원본 데이터베이스의 내용이 변경되었을 때, 기존에 있던 Redis 캐시 데이터를 어떻게 처리하는 가장 일반적이고 안전한가요?
3줄 요약
- 1원본은 변경되었으나 Redis에는 과거 데이터가 남아있으면 사용자에게 잘못된 정보를 보여주게 됩니다.
- 2이러한 데이터 불일치를 막기 위해 원본 변경 시 기존 캐시를 강제로 지우는 '캐시 무효화(Invalidation)'를 수행합니다.
- 3캐시 데이터를 직접 덮어쓰기보다는 아예 삭제하고 다음 번 조회 시 최신 데이터를 가져오게 하는 것이 구조적으로 안전합니다.