[필요성]
레디스를 사용하기 위해서는 왜 이런 전략이 필요할까?
데이터의 일관성이 필요하기 때문이다.
아래처럼 어떠한 데이터를 가져올 때 빈번하게 가져와야 하는 데이터는 캐시 메모리에 저장하여 더 빠른 처리가 가능하다.
만약 200을 가진 주소의 값을 300으로 바꿔야 한다면 어디부터 수정하고 어떤 방식으로 수정해야 할까?
메모리만 200을 300으로 바꾼다면 일관성이 깨지기 때문에 두 값을 모두 변경해야 한다는 사실은 자연스럽게 들 것이다. 이때 어떤 방법으로 데이터를 읽고 써야 하는지 그 효율을 위한 전략에 대해서 알아보고자 한다.
[캐시 히트/캐시 미스]
우선 전략을 세우기 전에 이러한 개념을 알고 가야 한다.
캐시 히트란 캐시 스토어(redis)에 데이터가 있을 경우 바로 가져오며 매우 빠른 속도를 보인다.
캐시 미스란 캐시 스토어에 데이터가 없을 경우 어쩔 수없이 DB를 거쳐서 가져오며 비교적 느린 속도를 보인다.
이러한 데이터의 정합성(다른 두 저장소에서 정보값이 서로 다른 현상)을 위해서 전략을 세우는 것이다.
[캐시 읽기 전략 - Look Aside 패턴]
Cach Aside 패턴이라고도 하며 가장 일반적인 패턴이다.
반복적인 읽기가 많은 호출에 적합하다.
예를 들어, 좋아요나 댓글 수 같은 게시글을 돌아다니면 자연스럽게 보이는 요소들이 이에 해당한다.
이 전략의 플로우는 아래와 같다.
1. 캐시에 저장된 데이터가 있는지 우선적으로 확인 (Chae Hit)
2. 캐시에 데이터가 없으면 DB에서 조회 (Cache Miss)
장점
캐시와 DB가 분리되어 가용되기 때문에 원하는 데이터만 별도로 캐시에 저장한다.
캐시가 DB와 분리되어 가용되기 때문에 캐시 장애 대비 구성을 할 수 있다. 만일 Redis가 다운되더라도 DB에서 데이터를 가져올 수 있어서 서비스 자체에는 문제가 없다는 뜻이다.
반복적으로 동일 쿼리를 수행하는 서비스에 적합한 아키텍처이다.
문제점
대신에 캐시에 붙어있던 connection이 많았다면, redis가 다운된 순간순간적으로 DB에 많은 요청이 들어오기 때문에 부하 가능성이 있다.
초기 조회 시 무조건 Data Store를 호출해야 하므로 단건 호출 빈도가 높은 서비스에는 적합하지 않다.
Cache Warming
위 같은 경우 DB에서 초기 조회시 미리 데이터를 캐시로 넣어주는 작업을 하는데 이게 Cache Warming이라고 한다.
이 작업을 수행하지 않으면 초기에 트래픽 급증 시 대량의 Cache Miss가 발생할 수 있다. 이를 Thundering Herd(인간들의 무리라는 의미)라고 한다.
캐시 자체는 용량이 작아 무한정으로 데이터를 들고 있을 수는 없기에 시간이 지나면 expire 되는 문제점이 있어 다시 Thundering Herd가 발생될 수 있기에 캐시의 TTL을 잘 조정할 필요가 있다.
[읽기 전략 - Read Through패턴]
캐시에서만 데이터를 읽어오는 전략이다. 이 방법또한 조회를 자주 하는 쿼리에서 적합하다.
Look Aside와 비슷하지만 데이터 동기화를 라이브러리 또는 캐시 제공자(MySQL)에게 위임하는 방식이 차이점이다.
데이터를 조회하는데 있어서 전체적으로 LookAside에 비해 속도가 느리다. 또한, 데이터 조회의 책임을 캐시에게만 부여하므로 Redis가 다운될 경우 차질이 생길 수 있다.
대신 캐시와 DB간의 데이터 동기화가 항상 이루어져 정합성문제는 발생하지 않는다.
플로우는 아래와 같다.
1. Redis에 검색하는 데이터가 있는지 확인 (Cache hit)
2. Redis에 없는 경우 캐시에서 DB에 있는 데이터를 조회하여 데이터 업데이트 (Cache miss)
3. Redis에서 데이터를 반환
[쓰기 전략 - Write Back]
Write Behind 패턴이라고도 불린다.
캐시와 DB 동기화를 비동기로 진행하기 때문에 동기화 과정이 생략된다.
데이터를 저장할 때 DB에 바로 쿼리를 날리지 않고, 캐시에 모아서 일정 주기 배치 작업을 통해 DB에 반영한다.
캐시에 모아놨다가 DB에 쓰기를 수행하기 때문에 쓰기 쿼리 회수 비용과 부하를 줄일 수 있다.
쓰기 작업이 빈번하면서 읽기를 하는데 많은 양의 자원이 소모되는 서비스에 적합하다.
데이터의 정합성이 확보되는 장점이 있다.
자주 사용되지 않는 불필요한 리소스가 저장되고 캐시에서 오류가 발생하면 데이터를 영구적으로 잃어버릴 수 있는 단점이 있다.
플로우는 다음과 같다.
1. 데이터들은 Redis에 저장된다.
2. 일정 시간에 주기적으로 수행되는 스케쥴링을 통해 DB에 한 번에 저장한다.
Wrtie Back방식은 데이터를 저장할 때 캐시에 저장하여 모아놨다가 주기적으로 DB에 쓰기 작업을 수행하므로 캐시가 일종의 대기열 역할(Queue)을 한다.
캐시에 Replication이나 Cluster구조를 적용함으로써 Cache 서비스의 가용성을 높이는 것이 좋으며, Read-Through(읽기 전략)와 결합하면 가장 최근에 업데이트 된 데이터를 항상 캐시에서 사용할 수 있는 방식에 적합하다.
Replicationdlsk Cluster구조에 대해서는 다음에 한 번 공부해 보고 포스팅할 생각이다!
[쓰기 전략 - Write Through]
데이터베이스와 Cache에 동시에 데이터를 동시에 저장하는 전략이다.
Read Through와 마찬가지로 DB동기화 작업을 캐시에서 책임을 맡는다.
DB와 캐시가 항상 동기화 되어 있어서 정합성에 문제가 없으며 항상 최신 상태로 유지할 수 있다.
데이터 유실이 발생하면 안 되는 상황에 적합하다.
하지만 Write Back처럼 자주 사용되지 않는 불필요한 리소스가 저장되며, 매 요청마다 두 번의 쓰기 작업이 발생하게 된다.
그래서 빈번하게 생성,수정 요청이 발생하는 서비스에서는 성능적인 부분에서 문제가 생길 수 있다.
기억장치 속도가 느릴 경우, 데이터를 기록할 때 CPU가 대기하는 시간이 필요하기 때문에 성능이 감소한다.
플로우는 다음과 같다.
1. Redis에 우선적으로 저장
2. 바로 DB에 저장
[쓰기 전략 - Write Around]
Write Through 보다 훨씬 빠르지만 모든 데이터를 DB에 저장하고 캐시를 갱신하지 않는 방법이다.
데이터의 정합성 문제가 발생할 수 있다.
Cache miss가 발생하는 경우에만 DB와 캐시에도 데이터를 저장한다.
데이터가 한 번 쓰여지고, 자주 조회되지 않거나 읽지 않는 상황에서 좋은 성능을 제공한다.
[쓰기 전략에서 주의할 점]
둘 다 불필요한 자원들이 저장되어 리소스 낭비가 발생하는 문제점이 있기 때문에, 이를 해결하기 위한 TTL(Time To Live)을 사용해서 자원 낭비를 해결해야 한다.
Write-Through / Read-Through 패턴을 함께 사용하면, 캐시의 최신 데이터 유지와 더불어 정합성의 이점을 얻을 수 있다.
[읽기 쓰기 조합]
1. Look Aside + Write Around
1. DB에 데이터를 쓰기
2. 레디스에서 먼저 읽기 수행. 만약, Cache Miss일 경우 DB에서 조회를 수행한다.
2. Read Through + Write Around
항상 DB에 쓰고, 캐시에서 읽을 때 항상 DB에서 조회를 먼저 수행하여 데이터 정합성을 완전히 대비할 수 있는 방법
1. DB에 데이터 쓰기
2. 캐시에서 조회시 DB에서 데이터의 정합성을 체크
3. 캐시에서 데이터 읽기
3. Read Through + Write Through
데이터를 쓸때 항상 캐시에 먼저 쓰므로, 읽어올 때 최신 캐시 데이터 보장
데이터를 쓸 때 항상 캐시에서 DB로 보내므로, 데이터 정합성 보장