본문 바로가기

Language/Spring

[Redis] 캐시란?

Redis 캐시(Cache) 전략

  • 캐시 전략은 웹 서비스 환경에서 시스템 성능 향상을 기대할 수 있는 중요한 기술
  • 일반적으로 캐시는 주기억장치(RAM)을 사용하기 때문에 데이터베이스보다 훨씬 빠르게 데이터 응답이 가능
  • 단, RAM은 용량이 한정적이기 때문에 모든 데이터를 캐시에 저장할 경우 용량 부족 상태가 발생
  • 따라서, 아래의 기준을 정해두어야 함
    • 어느 종류의 데이터를 저장할 것인가?
    • 얼만큼 데이터를 캐시에 저장할 것인가?
    • 얼마나 오래된 데이터를 캐시에서 삭제할 것인가?
[ DB I/O vs Redis 캐시 ]

ㅇ Database와 Redis의 저장 위치
 - 데이터베이스의 저장 위치  : 일반적으로 보조기억장치(HDD or SSD)
 - Redis(In-memory Data Store)의 저장 위치 : 주기억장치(RAM)

> Redis모든 데이터가 메모리에 저장되어 읽기/쓰기가 빠르고, 데이터 접근이 메모리에서 이루어지기 때문에 성능이 매우 우수

> Database디스크에서 읽기/쓰기를 수행하기 때문에 메모리(RAM)에 비해 상대적으로 속도가 느리며, 디스크 I/O는 물리적 제약과 병목 현상이 발생할 수 있음

따라서, Redis 캐시 전략 사용 시 아래의 장점을 가질 수 있음
- 빠른 데이터 액세스 : 데이터 액세스 시간이 크게 단축
- 부하 분산 : DB에 대한 요청 수를 줄여 데이터베이스의 부하를 분산
- 응답 시간 단축 : 사용자 요청에 대한 응답 시간이 크게 개선

 

Cache Hit / Cache Miss
  • Redis 캐시에는 Cache Hit와 Cache Miss라는 개념이 존재
  • Cache Hit : 캐시 스토어(Redis)에 데이터가 있을 경우 (빠름)
  • Cache Miss : 캐시 스토어(Redis)에 데이터가 없을 경우 Database에서 가져옴 (느림)


캐싱 전략 패턴 종류

  • 캐시를 이용할 때 발생하는 문제점데이터 정합성 문제
    • 데이터 정합성 ⇒ 어느 한 데이터가 캐시와 데이터베이스 두 곳에 같은 데이터임에도 불구하고 데이터의 값이 다른 현상을 의미
    • Ex) 캐시의 재고 데이터 3개, 데이터베이스의 재고 데이터 30개
  • 기존에 데이터베이스만 이용할 때에는 데이터베이스에 읽기/쓰기를 하였기 때문에 데이터 정합성 문제가 발생하지 않았지만, 두 개의 저장소를 사용하다 보니 데이터 정합성 문제가 발생한 것
  • 따라서, 적절한 캐시 읽기 전략(Cache Read Strategy)과 캐시 쓰기 전략(Cache Write Strategy)을 통해 캐시와 DB간의 데이터 불일치 문제를 극복하고 빠른 성능까지 가지도록 해야 함

캐시 읽기 전략(Cache Read Strategy)

Look Aside(Cache Aside) 패턴
  • 데이터 조회 → 캐시 확인 → 캐시에 없을 경우 DB 조회 → 조회한 데이터 캐시에 업데이트
  • 반복적인 읽기가 많은 호출에 적합
  • 캐시와 DB가 분리되어 가용되기 때문에 원하는 데이터만 별도로 구성하여 캐시에 저장
  • 캐시와 DB가 분리되어 가용되기 때문에 캐시 장애 대비 구성이 되어 있기 때문에 만일 redis가 다운 되더라도 DB에서 데이터를 가져올수 있어 서비스 자체는 문제가 없음
  • 단, 캐시에 붙어있던 connection이 많을 경우 redis가 다운된 순간 순간적으로 DB로 몰려서 부하 발생

  1. Redis Cache에 검색하는 데이터가 있는 지 확인 (Cache Hit)
  2. Redis Cache에 검색하는 데이터가 없을 경우 Database 확인 (Cache Miss)
  3. DB에서 조회한 데이터를 Redis Cache에 업데이트 (Server → Redis)
  • Look Aside Cache 패턴은 애플리케이션에서 캐싱을 이용할 때 일반적으로 사용되는 기본적인 캐시 전략
  • 이 방식은 캐시에 장애가 발생하더라도 DB에 요청을 전달함으로써 캐시 장애로 인한 서비스 문제는 대비 가능
  • 단, Cache Store와 Data Store(DB)간 정합성 유지 문제가 발생할 수 있으며, 초기 조회 시 무조건 Data Store를 호출 해야 하므로 단건 호출 빈도가 높은 서비스에 적합하지 않음
  • 즉, 반복적으로 동일 쿼리를 수행하는 서비스에 적합한 아키텍처
  • 이런 경우 DB에서 캐시로 데이터를 미리 넣어주는 작업을 하기도 하는데 이를 Cache Warming이라고 함
[ Cache Warming ]

- 미리 Cache로 DB의 데이터를 밀어 넣어두는 작업을 의미
- 이 작업을 수행하지 않으면 서비스 초기에 트래픽 급증시 대량의 cache miss 가 발생하여 데이터베이스 부하가 급증 할 수 있음 (Thundering Herd)
- 다만, 캐시 자체는 용량이 작아 무한정으로 데이터를 들고 있을수는 없어 일정시간이 지나면 expire되는데, 그러면 다시 Thundering Herd가 발생될 수 있기 때문에 캐시의 TTL을 잘 조정해야 함

Read Through 패턴
  • 데이터 조회 → 캐시 확인 → 캐시에 없을 경우 DB 조회 → 조회한 데이터 캐시에 업데이트 → 서버에 반환
  • 캐시에서만 데이터를 읽어오는 전략 (inline cache)
  • Look Aside 와 비슷하지만 데이터 동기화를 라이브러리 또는 캐시 제공자에게 위임하는 방식이라는 차이
  • 따라서 데이터를 조회하는데 있어 전체적으로 속도가 느림
  • 또한 데이터 조회를 전적으로 캐시에만 의지하므로, redis가 다운될 경우 서비스 이용에 차질이 생길수 있음
  • 대신에 캐시와 DB간의 데이터 동기화가 항상 이루어져 데이터 정합성 문제에서 벗어날수 있음
  • 역시 읽기가 많은 워크로드에 적합

  1. Redis Cache에 검색하는 데이터가 있는 지 확인 (Cache Hit)
  2. Redis Cache에 검색하는 데이터가 없을 경우 Database를 조회하여 자체 업데이트 (Cache Miss)
  3. Cahe에서 데이터를 가져옴
  • Read Through 방식은 Cache Aside 방식과 비슷하지만, Cache에 저장하는 주체Server이냐 또는 Cache 자체이냐에서 차이 발생
  • 이 방식은 직접적인 데이터베이스 접근을 최소화하고 Read에 대한 소모되는 자원을 최소화 가능
  • 하지만 캐시에 문제가 발생하였을 경우 이는 바로 서비스 전체 중단으로 빠질 수 있기 때문에 redis와 같은 구성 요소 Replication 또는 Cluster로 구성하여 가용성을 높여야 함
이 방식 또한 Cache Warming을 수행하는 것이 좋다고 함

캐시 쓰기 전략(Write Cache Strategy)

Write Back(Write Behind) 패턴
  • 데이터 전송   Redis에 저장 일정 시간(스케쥴링)마다 DB에 저장
  • 캐시와 DB 동기화를 비동기하기 때문에 동기화 과정 생략
  • 데이터를 저장할때 DB에 바로 쿼리하지않고 캐시에 모아서 일정 주기 배치 작업을 통해 DB에 반영
  • 캐시에 모아놨다가 DB에 쓰기 때문쓰기 쿼리 회수 비용과 부하를 줄일 수 있음
  • Write가 빈번하면서 Read를 하는데 많은 양의 Resource가 소모되는 서비스에 적합
  • 데이터 정합성 확보
  • 자주 사용되지 않는 불필요한 리소스 저장
  • 캐시에서 오류가 발생하면 데이터 영구 소실

  1. 모든 데이터를 Cache에 저장
  2. 일정 시간마다 DB에 Query 전송
  • Write Back 방식은 데이터를 저장할때 DB가 아닌 먼저 캐시에 저장하여 모아놓았다가 특정 시점마다 DB로 쓰는 방식으로 캐시가 일종의 Queue 역할
  • 캐시에 데이터를 모았다가 한 번에 DB에 저장하기 때문에 DB 쓰기 횟수 비용과 부하가 감소될 수 있으나 데이터를 옮기기 전에 캐시 장애가 발생하면 데이터 유실이 발생할 수 있다는 단점이 존재
  • 단, 오히려 반대로 데이터베이스에 장애가 발생하더라도 지속적인 서비스를 제공할 수 있도록 보장하기도 함
[ Tip ]

- 이 전략 또한 캐시에 Replication이나 Cluster 구조를 적용함으로써 Cache 서비스의 가용성을 높이는 것이 좋음
- 캐시 읽기 전략인 Read-Through와 결합하면 가장 최근에 업데이트된 데이터를 항상 캐시에서 사용할 수 있는 혼합 워크로드에 적합

Write Through 패턴
  • 데이터 전송 → Redis에 저장 → 즉시 DB에 저장
  • 데이터베이스와 Cache에 동시에 데이터를 저장하는 전략
  • 데이터를 저장할 때 먼저 캐시에 저장한 다음 바로 DB에 저장 (모아놓았다가 나중에 저장이 아닌 바로 저장)
  • Read Through 와 마찬가지로 DB 동기화 작업을 캐시에게 위임
  • DB와 캐시가 항상 동기화 되어 있어, 캐시의 데이터는 항상 최신 상태로 유지
  • 캐시와 백업 저장소에 업데이트를 같이 하여 데이터 일관성을 유지할 수 있어서 안정적
  • 데이터 유실이 발생하면 안 되는 상황에 적합
  • 자주 사용되지 않는 불필요한 리소스 저장
  • 매 요청마다 두번의 Write가 발생하게 됨으로써 빈번한 생성, 수정이 발생하는 서비스에서는 성능 이슈 발생
  • 기억장치 속도가 느릴 경우 데이터를 기록할 때 CPU가 대기하는 시간이 필요하기 때문에 성능 감소

  1. DB에 저장할 데이터가 있을 경우 Cache에 먼저 저장
  2. 즉시 Cache에서 DB에 저장
  • Write Through 패턴은 Cache에도 반영하고 Data Store에도 동시에 반영하는 방식
    (Write Back은 일정 시간을 두고 나중에 한꺼번에 저장)
  • 그래서 항상 동기화가 되어 있어 항상 최신정보를 가지고 있다는 장점을 가짐
  • 하지만 결국 저장할때마다 캐시 저장 →  DB저장의 2단계 과정을 거쳐치기 때문에 상대적으로 느리며, 일단 무조건 Cache에 저장하기 때문에 캐시에 넣은 데이터를 저장만 하고 사용하지 않을 가능성이 있어서 리소스 낭비 가능성이 있음
[ Tip ]

Write Throuth 패턴과 Write Back 패턴 둘 다 모두 자주 사용되지 않는 데이터가 저장되어 리소스 낭비가 발생되는 문제점을 안고 있기 때문에, 이를 해결하기 위해 TTL을 반드시 사용하여 사용되지 않는 데이터를 반드시 삭제해야 함 [expire]

Write Around 패턴
  • Write Through 보다 훨씬 빠름
  • 모든 데이터는 DB에 저장 (캐시를 갱신하지 않음)
  • Cache miss가 발생하는 경우에만 DB와 캐시에도 데이터를 저장
  • 따라서 캐시와 DB 내의 데이터가 다를 수 있음 (데이터 불일치)

  1. 모든 데이터는 DB에 저장
  • Write Around 패턴은 속도가 빠르지만 cache miss가 발생하기 전에 데이터베이스에 저장된 데이터가 수정되었을 때 사용자가 조회하는 cache와 데이터베이스 간의 데이터 불일치가 발생
  • 따라서 데이터베이스에 저장된 데이터가 수정, 삭제될 때마다 Cache 또한 삭제하거나 변경해야 하며, Cache의 expire를 짧게 조정하는 식으로 대처
[ Tip ]

- Write Around 패턴은 주로 Look aside, Read through와 결합해서 사용
- 데이터가 한 번 쓰여지고, 덜 자주 읽히거나 읽지 않는 상황에서 좋은 성능을 제공

캐시 읽기 + 쓰기 전략 조합

Look Aside + Write Around 조합
    • 가장 일반적으로 쓰이는 조합
    • 전체 흐름 요약
      • 조회 시: 캐시에서 데이터를 먼저 조회하고, 없으면 데이터베이스에서 조회. 단, 조회 시에는 캐시에 저장하지 않음
      • 저장 시: 데이터베이스에 직접 저장하고, 캐시는 업데이트하지 않음
      • 캐시 갱신: 캐시는 다시 데이터가 조회될 때만 갱신


Read Through + Write Around 조합
    • 항상 DB에 쓰고, 캐시에서 읽을때 항상 DB에서 먼저 읽어오므로 데이터 정합성 이슈에 대한 완벽한 안전 장치를 구성 가능
    • 전체 흐름 요약
      • 데이터 조회 : 캐시에서 먼저 데이터를 찾고, 없으면 캐시가 데이터베이스에서 데이터를 조회하여 반환하고 캐시에도 저장
      • 데이터 저장 시 : 데이터베이스에만 저장하고, 캐시는 업데이트하지 않음
      • 캐시 갱신 : 캐시된 데이터가 변경되지 않은 상태로 남아있다가, 다음에 해당 데이터를 조회할 때 갱신


Read Through + Write Through
    • 데이터를 쓸 때 항상 캐시에 먼저 쓰므로, 읽어올때 최신 캐시 데이터 보장
    • 데이터를 쓸 때 항상 캐시에서 DB로 보내므로, 데이터 정합성 보장
    • 전체 흐름 요약
      • 데이터 조회 시 : 캐시에서 데이터를 먼저 조회. 캐시 미스가 발생하면 캐시가 데이터베이스에서 데이터를 가져와 캐시에 저장하고 클라이언트에 반환
      • 데이터 저장 시 : 클라이언트가 데이터를 저장할 때, 캐시와 데이터베이스 모두 동시에 저장되어 항상 최신 상태 유지
      • 캐시 갱신 : 데이터가 변경될 때마다 캐시도 즉시 업데이트되므로, 캐시와 데이터베이스는 항상 일관성을 유지


참고 자료

https://inpa.tistory.com/entry/REDIS-%F0%9F%93%9A-%EC%BA%90%EC%8B%9CCache-%EC%84%A4%EA%B3%84-%EC%A0%84%EB%9E%B5-%EC%A7%80%EC%B9%A8-%EC%B4%9D%EC%A0%95%EB%A6%AC#%EC%BA%90%EC%8B%9C_%EC%A0%80%EC%9E%A5_%EB%B0%A9%EC%8B%9D_%EC%A7%80%EC%B9%A8