
트래픽이 많은 서비스에서 Redis를 도입하는 가장 큰 이유는 캐시를 통해 응답 속도를 높이고 데이터베이스 부하를 줄이기 위해서다. 그런데 단순히 Redis에 값을 넣고 빼는 수준으로만 사용하면 어느 순간부터 데이터 불일치나 캐시 미스(Cache Miss) 문제에 부딪힌다. 그래서 실무에서는 Redis 캐시 전략을 의도적으로 설계하고, 대표 패턴인 Cache Aside와 Write Through를 상황에 맞게 조합해 사용한다. 이 글에서는 두 패턴의 개념과 동작 방식, 장단점, 그리고 설계 시 고려해야 할 포인트를 차근차근 정리해본다.
Redis 캐시 전략 CacheAside 개념
먼저 Redis 캐시 전략의 큰 그림 속에서 Cache Aside가 어떤 위치를 차지하는지 이해하는 것이 좋다. Cache Aside 패턴은 말 그대로 “캐시는 옆에 두고 필요할 때만 사용하는” 전략이다. 요청이 들어왔을 때 가장 먼저 캐시(Redis)를 조회하고, 캐시에 없을 경우에만 데이터베이스를 조회한 뒤 그 결과를 다시 캐시에 채워 넣는 방식이다. 즉 애플리케이션이 캐시와 DB 사이를 직접 조율하는 주체가 된다. 이 구조의 핵심은 캐시가 절대적인 진실(Source of Truth)이 아니라는 점이다. 진짜 데이터의 기준은 항상 데이터베이스에 있고, Redis는 빠른 응답을 위한 보조 수단일 뿐이다.
읽기 요청 흐름은 보통 다음과 같다. 1) 클라이언트 요청 → 2) Redis에서 key 조회 → 3) 값이 있으면 바로 반환 → 4) 없으면 DB 조회 → 5) 조회 결과를 Redis에 저장 → 6) 클라이언트에게 응답. 이 덕분에 자주 조회되는 데이터는 자동으로 캐시에 쌓이고, 이후에는 거의 Redis만 조회하면서 높은 성능을 얻을 수 있다. 쓰기의 경우에는 보통 DB를 기준으로 처리하고, 캐시는 무효화하거나 필요한 시점에 다시 채워 넣는 패턴을 많이 쓴다. 그렇기 때문에 Cache Aside는 “읽기 중심 서비스”, “조회가 압도적으로 많은 서비스”에서 특히 잘 어울린다.
실무에서 Cache Aside를 사용할 때 중요한 포인트는 캐시 만료 전략이다. TTL을 적절히 설정하지 않으면 오래된 값이 캐시에 남아서 사용자에게 보여질 수 있다. 반대로 TTL을 너무 짧게 설정하면 캐시 히트율이 떨어진다. 또한 쓰기 이후 캐시 삭제 타이밍도 중요하다. 보통 “DB 업데이트 → 캐시 삭제” 순서로 처리해 데이터 정합성을 최대한 맞추려 한다. 이처럼 Cache Aside는 구조가 단순하면서도 유연해서 가장 널리 사용되는 Redis 캐시 전략이라고 볼 수 있다.
Cache Aside 전략 동작방식
Cache Aside 전략의 동작 방식은 읽기와 쓰기로 나누어 보는 것이 이해하기 쉽다. 읽기 요청이 들어오면 애플리케이션은 먼저 Redis에 해당 key가 존재하는지 확인한다. 값이 있다면 캐시 히트(Cache Hit)로 간주하고 그대로 반환하므로 DB를 거치지 않는다. 이 단계에서 응답 속도가 가장 빠르며, Redis의 장점을 가장 잘 살릴 수 있다. 반대로 값이 없다면 캐시 미스(Cache Miss)가 발생한 것이고, 애플리케이션은 DB를 조회해 결과를 가져온다. 그리고 이 데이터를 Redis에 저장해 두고, 클라이언트에게 응답을 돌려준다. 이 과정을 통해 자주 사용되는 데이터는 자연스럽게 캐시에 축적된다.
쓰기 흐름은 조금 더 선택지가 있다. 대표적인 방식은 “DB를 기준으로 쓰고, 캐시는 지우거나 갱신한다”는 원칙이다. 예를 들어 특정 상품의 재고를 수정한다고 가정해 보자. 1) DB에서 해당 상품 재고를 업데이트하고, 2) Redis에 저장된 해당 상품 캐시를 삭제하거나 새 값으로 덮어쓴다. 이렇게 하면 다음 읽기 요청 시에 캐시 미스가 발생하고, DB에서 최신 값을 불러와 캐시를 다시 채우게 된다. 이 과정에서 잠깐의 짧은 틈에는 이전 값이 보일 수 있지만, 대부분의 서비스에서 수용 가능한 수준이다.
Cache Aside 전략의 장점은 설계가 직관적이고 기존 코드에 점진적으로 붙이기 쉽다는 것이다. 기존 DB 조회 코드 앞뒤에 Redis 조회와 저장 로직만 끼워 넣으면 되기 때문에 도입 비용이 낮다. 다만 단점도 존재한다. 캐시 미스가 집중되는 상황에서는 여전히 DB 부하가 높아질 수 있고, 캐시와 DB 사이에 아주 짧은 시간 동안 데이터 불일치가 생길 수 있다. 또한 코드 곳곳에 동일한 캐시 처리 로직이 퍼지기 쉬워, 이를 공통 모듈로 잘 묶어두는 것도 실무 설계에서 중요한 포인트다.
Write Through 전략 특징 정리
Write Through 전략은 Cache Aside와 달리, 쓰기 연산을 기준으로 캐시와 DB를 항상 함께 업데이트하는 방식이다. 데이터를 변경할 때 “캐시에 먼저 쓰고, 그 다음 DB에 쓰거나 동시에 쓰는” 흐름을 가진다. 즉 애플리케이션 입장에서는 항상 캐시로 쓰기를 보내고, 캐시가 내부적으로 DB와 동기화되도록 구성하는 개념에 가깝다. 이 패턴의 핵심 목표는 “언제 읽더라도 캐시에 최신 데이터가 있다”는 상태를 유지하는 것이다.
Write Through 전략의 장점은 읽기 시점의 일관성이 매우 높다는 점이다. 쓰기가 발생할 때마다 캐시와 DB가 같이 갱신되므로, 읽기 요청은 항상 캐시에서 최신 값을 가져올 수 있다. 따라서 조회 비율이 높고, 데이터 정합성 요구 수준이 높은 도메인에서는 매력적인 선택지가 될 수 있다. 예를 들어 사용자 프로필처럼 변경 빈도는 낮지만, 항상 최신 정보가 보여야 하는 경우에 적합하다.
하지만 Write Through는 구현 난이도와 비용이 Cache Aside보다 높은 편이다. 모든 쓰기 경로에서 캐시를 반드시 거쳐야 하고, 캐시와 DB 간 쓰기 실패 시 재시도나 롤백 전략도 고려해야 한다. 쓰기 트래픽이 많은 서비스에서는 캐시와 DB에 모두 쓰기 부담이 발생해 성능 이슈로 이어질 수도 있다. 또한 Redis 단독으로는 완전한 Write Through를 구현하기 어렵기 때문에, 애플리케이션 레벨에서 “캐시에 쓰고, DB에 쓰고, 예외 처리까지” 책임져야 하는 경우가 많다. 그만큼 코드 설계와 테스트가 더 필요하다는 점을 기억해야 한다.
Cache Aside Write Through 비교
Cache Aside Write Through 두 전략을 비교할 때 가장 먼저 봐야 할 것은 “누가 진짜 데이터의 기준인가?”라는 질문이다. Cache Aside에서는 데이터베이스가 절대적인 기준이고, 캐시는 단순히 빠른 조회를 위한 복제본 역할을 한다. 캐시가 비어 있거나 오래된 값이어도 치명적이지 않으며, 언젠가는 DB에서 값을 다시 가져와 캐시가 채워진다는 전제를 깔고 있다. 반면 Write Through에서는 캐시까지도 거의 진실에 가까운 상태로 유지하려고 한다. 쓰기 시점에 캐시와 DB가 같이 갱신되므로, 읽기 시점에 캐시만 보고도 안심할 수 있는 환경을 추구한다.
성능 관점에서 보면 Cache Aside는 읽기 성능 최적화에 강점이 있고, Write Through는 읽기 성능과 데이터 일관성 사이의 균형에 초점을 맞춘다. Cache Aside에서는 캐시 미스가 발생할 때만 DB를 조회하기 때문에 읽기가 많은 서비스에서 DB 부하를 크게 낮출 수 있다. Write Through는 쓰기 시점에 캐시와 DB를 모두 업데이트하기 때문에 쓰기 비용이 상대적으로 크다. 따라서 쓰기가 많고 강한 일관성이 꼭 필요하지 않은 도메인이라면 굳이 Write Through를 선택할 이유는 크지 않다.
운영 측면에서도 차이가 있다. Cache Aside는 구현이 상대적으로 단순하고 문제가 생기면 캐시를 비우고 DB를 기준으로 다시 채우는 전략이 통한다. Write Through는 캐시와 DB가 함께 깨질 수 있기 때문에 장애 상황에서 복구 전략을 더 정교하게 설계해야 한다. 결국 어떤 전략이 “정답”이라기보다, 특정 도메인의 읽기·쓰기 패턴, 정합성 요구 수준, 장애 허용 범위를 고려해 두 전략을 적절히 조합하는 것이 실무적인 접근이다.
Redis 캐시 전략 설계 시 주의점
마지막으로 Redis 캐시 전략을 설계할 때 공통적으로 주의해야 할 점들을 정리해보자. 먼저 “무엇을 캐싱할 것인가”를 명확히 정의해야 한다. 모든 데이터를 Redis에 넣는 것은 오히려 비용 낭비가 될 수 있다. 조회가 잦고, 데이터 크기가 상대적으로 작고, 약간의 지연된 일관성을 허용할 수 있는 도메인이 캐시 대상 1순위다. 반대로 실시간 정합성이 절대적인 결제, 재고, 회계 등은 캐시를 쓰더라도 매우 신중한 설계가 필요하다.
둘째, TTL과 무효화 전략이다. Cache Aside든 Write Through든 결국 캐시 무효화는 피할 수 없는 주제다. TTL을 너무 길게 잡으면 오래된 데이터가 남고, 너무 짧게 잡으면 히트율이 떨어진다. 또한 대량의 키가 동시에 만료되면 순간적으로 DB에 부하가 몰릴 수 있으므로 만료 시간을 분산시키는 것도 하나의 팁이다. 셋째, 장애 상황을 가정한 설계가 필요하다. Redis가 잠시 내려가도 서비스가 완전히 마비되지 않도록 “캐시가 없어도 최소한 DB로는 동작하도록” 방어 로직을 넣는 것이 좋다. 마지막으로, 캐시 코드는 여기저기 흩어지지 않도록 공통 모듈이나 유틸 클래스로 캡슐화해 두어야 전략 변경이 필요할 때 전체 코드를 한 번에 수정할 수 있다. 이런 점들을 신경 써서 설계하면 Redis 캐시 전략은 서비스 성능을 끌어올리는 든든한 무기가 될 수 있다.