본문 바로가기

Java/Spring

Redis 캐싱 적용과 TTL, 캐시 전략 패턴 활용기

개요

프로젝트가 1차 개발을 마치고 2차 개발에 들어가던 시점, 회원 수가 200명에서 최대 2만 명까지 늘어날 수 있다는 요구사항을 받았다. 이에 따라 사용자 경험 개선과 성능 강화를 위해 Redis 도입을 검토했지만, 고객사는 추가 비용을 우려해 쉽게 동의하지 않았다.

 

당시 서버 환경은 AWS ECS Fargate 기반이었고, 가장 단순한 방법은 ElastiCache를 사용하는 것이었다. 하지만 비용이 만만치 않았기 때문에, 결국 비용을 줄이기 위해 EC2에 Redis를 직접 설치하는 방법을 택했다. 이 과정에서 초기 과정이라 모니터링을 따로 붙이진 못했다.하지만 고객사의 상황에 맞춰 성능 개선과 비용 절감을 동시에 가져갈 수 있었다.

 

오늘은 이렇게 적용된 Redis가 어떻게 구성되어 있고, 언제 사용하는지 정리해보려고 한다.

 

캐시(Cache)

우선 캐시(Cache)란,
CPU와 RAM 사이처럼 속도가 다른 장치 간의 병목 현상을 줄이기 위해 도입된 중간 계층이다.

소프트웨어에서는 자주 조회되는 데이터를 DB 대신 빠른 캐시 저장소(예: Redis)에 담아두고 재사용함으로써 성능을 크게 개선할 수 있다.

하드웨어 : CPU ↔ RAM 사이의 캐시 메모리
소프트웨어 : DB ↔ 애플리케이션 사이의 Redis, Memcached 

이 말은 DB응답 부하 감소응답시간이 향상된다는 장점이 있다.

 

하지만 캐시가 좋다고 해서 적용하기보다 여러 가지 고려할 것이 있다.

  • 어떤 전략을 사용할지
  • 어떤 데이터를 캐싱할지
  • 캐시서버를 따로 둘지 아니면 애플리케이션 서버에 둘지 (Local Cache vs Global Cache)
  • 캐시 저장소 중 어떤 걸 사용할지

캐시 전략패턴에 들어가기 전 2가지를 알아두면 좋다.

 

Cache hit : 캐시 스토어(Redis)에 데이터가 있으면 바로 가져옴

Cache miss : 캐시 스토어(Redis)에 데이터가 없으면 DB에서 가져오고 가져온 데이터를 캐시에 저장한 후 반환 

 


캐시(Cache) 전략 패턴 종류

캐시를 이용하면 고려할 것이 있는데 바로 데이터 정합성 문제다.

데이터 정합성은 캐시와 데이터베이스에서 같은 데이터임에도 서로 다른 현상을 말한다. 이전에는 그냥 DB에서 데이터 조회와 작성을 처리하다가 캐싱을 도입하면서, 또 다른 저장소를 이용하기 때문에 같은 데이터라도 두 저장소에서 서로 다를 수 있는 현상이 일어난다.

 

이에 따라 캐시 읽기 전략(Read Cache Strategy)과 캐시 쓰기 전략(Write Cache Strategy)을 통해 데이터 불일치를 방지하면서 빠른 성능 최적화를 위해 노력이 필요하다.

 

캐시 읽기 전략(Read Cache Strategy)

 

Look Aside 패턴

  • 애플리케이션에서 데이터를 찾을 때 캐시에 저장된 데이터가 있는지 우선적으로 확인하는 전략.
  • Cache Aside 패턴이라고도 불림
  • 반복 적인 읽기가 많은 호출에 적합 (실제 프로젝트 진행 시 문제 데이터가 큰 HTML로 이루어졌는데 사용자 노출 후 수정은 없어 적용)
  • 캐시와 DB 가 분리되어 가용되기 원하는 데이터만 저장가능하고 캐시 장애 대비 구성이 되어 있다. (Redis다운 시 DB데이터 가져옴) 

Look Aside 패턴

장점 : 원하는 데이터만 저장해 메모리 사용 최적화와 DB 접근을 최소화할 수 있다.

단점 : 캐시미스 (Cache miss)가 발생하면 DB에 접근하는 시간이 있어 초기 요청 시 응답이 느리다.

 

위에 말한 단점으로 인해 캐시로 미리 데이터를 넣어주기도 하는데 이걸 Cache Warming이라고 한다.

 

Cache Warming 

  • 미리 Cache로 DB 데이터를 넣어주는 작업을 의미하며, 이작업을 하면 서비스 초기 트래픽 급증시 데이터 부하를 방어할수 있지만 캐시 자체의 용량은 한정되어있어 일정 시간이 지나면 expire된다. 그러면 다시 Thundering Herd가 발생 될 수 있어 캐시의 TTL을 잘 조정 해야한다.

 

Read Through 패턴

  • 캐시에만 데이터를 읽어오는 전략 (조회 요청이 오면 캐시가 DB와 동기화 책임을 지고 데이터를 가져오는 구조)
  • Look Aside와 비슷하지만 데이터 동기화를 라이브러리 또는 캐시 제공자에게 위임 하는 차이 이에따라 데이터 조회가 전체적으로 느림
  • 캐시와 DB가 데이터 동기화 가 항상 이우어져 있지만 캐시에만 의지해 Redis 다운 시 서비스 이용에 차질이 생길 수 있음
  • 이것도 반복 적인 읽기가 많은 호출에 적합

Read Through 패턴

Look Aside 와 방식은 비슷하지만 저장하는 주체가 server인지 DB자체인지에대한 차이가 있다.

이 방식은 직접적인 DB 접근 최소화와 읽기에대한 소모되는 자원을 최소화 할수 있다. 하지만 캐시 문제 발생 시 서비스 전체 중단이 될수도 있다.

 


캐시 쓰기 전략 (Write Cache Strategy)

 

Write Back 패턴

  • 데이터를 저장할때 바로 DB에 저장하지 않고, 캐시에 모아 일정 주기 배치 작업을 통해 DB에 반영한다.
  • 캐시와 DB 동기화를 비동기하기 때문에 동기화 과정이 생략 된다.
  • 쓰기가 빈번하고 읽기를 하는데 많은 리소스가 소모되는 서비스에 적합하며, 캐시에 모아놨다가 DB에 쓰기 때문에 쓰기쿼리 회수 비용과 부하를 줄일 수 있다.
  • 하지만 캐시에서 오류가 발생하면 데이터를 영구 소실 한다.

Write Back 패턴

Write Back패턴은 DB 에 저장할때 캐시에 저장했다가 특정 시점 마다 DB로 쓰는 방식으로 캐시가 일종의 Queue의 역할을 겸하게 된다.

 

DB쓰기 횟수 비용과 부하를 줄일 수 있지만 데이터를 옮기기전에 혹시나 캐시 장애가 발생하면 데이터가 유실될 수 있다. 하지만 반대로 DB가 장애 발생 시 지속적인 서비스를 제공할 수 있다는 장점도 있긴하다.

 

Write Through 패턴

  • DB와 Cache에 동시에 저장하는 전략
  • 데이터를 저장할 때 먼저 캐시에 저장 후 DB에 저장 (모아놓지 않고 저장)
  • Read Through와 같이 DB 동기화를 캐시에게 위임 캐시와 백업 저장소에 업데이트를 같이 하여 데이터 일관성 유지 가능
  • 데이터 유실이 발생하면 안되는 금융 시스템등 에 적합
  • 매 요청 시 2번의 쓰기와 빈번한 생성, 수정으로 성능 이슈가 발생 되고, 기억장치가 느리면 데이터 기록시 CPU가 대기하는 시간 때문에 성능이 감소됨

Write Through 패턴

Write Through 패턴은 Cache Store에도 반영하고 Data Store에도 동시에 반영하는 방식이다. (Write Back은 일정 시간을 두고 나중에 한꺼번에 저장)

항상 동기화가 되어 최신 정보를 가지고 있지만 저장할때 2단계를 거치기 때문에 상대적으로 느리며, 무조건 Cache에 저장하기 떄문에 캐시에 넣은 데이터를 저장만 하고 사용 안할 가능성도 존재한다.

 

Write Around 패턴

  • Write Through 보다 훨씬 빠름
  • 모든 데이터는 DB에저장하고 Cache miss가 발생하는 경우에만 DB와 캐시에 모두 저장함

Write Around 패턴

 


Write Around 패턴은 속도는 빠르지만 Cache miss 발생 전 데이터베이스에 저장된 데이터가 수정되면 사용자가 조회할때 DB와 Cache 간의 데이터 불일치가 발생하게 된다.

 

따라서 DB에 저장된 데이터가 수정, 삭제 될때마다 Cache 또한 삭제와 변경하며, Cache의 expire를 짧게 조정하는 식으로 대처해야한다.

 

난 어떤걸 썻을까?

캐시 읽기 + 쓰기 전략으로 Look Aside(읽기) + Write Around(쓰기) 전략을 조합해, 조회는 빈번하지만 수정은 적은 데이터(상품, 시험지 등)에 캐시를 적용했다. 캐시에 TTL(Time To Live) 설정해 일정 시간이 지나면 캐시가 만료되고 이후 조회 시 DB에서 가져와 다시 갱신되도록 했으며, 상품 정보 수정·삭제 시에는 @CacheEvict로 무효화하여 데이터 정합성과 운영 안정성을 확보하였다. 이를 통해 캐싱된 API 조회 응답 속도가 평균 30~70ms 수준으로 단축되어 사용자 경험 개선과 안정적인 서비스 제공이 가능해졌다.

 

정리

 

       전략                           특징                                           장점                                                단점                              적합한 경우

Look Aside 캐시에 있으면 읽고, 없으면 DB→캐시 저장 원하는 데이터만 캐싱,
장애 시 DB fallback 가능
초기 Cache miss 시 느림 자주 읽히는 데이터,
읽기 위주 서비스
Read Through 캐시가 DB 접근·동기화 담당 일관성 유지 쉬움 Redis 장애 시 서비스 중단 위험 읽기 요청 많고 데이터 일관성 중요한 경우
Write Back 먼저 캐시에 쓰고, 주기적으로 DB 반영 쓰기 부하 감소 장애 시 데이터 유실 위험 로그성 데이터, 집계성 데이터
Write Through 캐시+DB 동시 저장 일관성 항상 유지 쓰기 성능 저하 금융/거래 시스템
Write Around DB에만 저장,
Cache miss 시 캐시에 적재
쓰기 성능 최적 캐시 불일치 발생 가능 읽기 빈도 낮은 데이터