레디스는 인메모리 데이터 스토어로, 디스크 기반의 데이터베이스보다 빠르게 데이터를 응답할 수 있어 고객에게 빠르게 서비스를 제공할 수 있다.
하지만 메모리 용량은 16GB ~ 32GB 정도로 제한적이기 때문에 모든 데이터를 저장하기에는 용량 부족 현상이 일어날 수 있다.
따라서 어떤 데이터를 저장할 것인지, 얼마나 데이터를 캐싱할 것인지, 어떤 데이터를 제거할 것인지에 대한 전략이 필요하다.
읽기 전략
- Look-Aside : 서버가 캐시를 먼저 조회하고, 캐시에 없을 경우 데이터베이스를 조회한다.
- Read-Through : 캐시를 통해서만 데이터를 읽어오는 전략이다.
쓰기 전략
- Write-Back : 모든 데이터를 캐시에 저장하고, 일정 시간 뒤에 데이터베이스에 저장한다.
- Write-Through : 데이터를 캐시와 데이터베이스에 동시에 저장한다.
- Write-Around : 모든 데이터를 데이터베이스에 저장한다.
Look-Aside
- Lazy 로딩 읽기 전략으로 가장 많이 사용되는 전략이다.
- 레디스를 먼저 확인하고, 있으면 조회하고 없으면 데이터베이스를 조회한 이후에 레디스에 저장한다.
1. 캐시에 데이터가 있는지 확인한다.
2. 데이터가 캐싱되어 있으면, 즉시 클라이언트에게 해당 데이터를 제공한다. (cache hit)
3. 데이터가 캐싱되어 있지 않다면, 서버는 데이터베이스에서 데이터를 가져오기 위해 쿼리를 보내고 클라이언트에게 응답한다.
3-1. 이후 데이터를 캐시에 저장한다. (cache miss)
4. 동일한 요청에 대해서는 캐시에서 즉시 데이터를 제공할 수 있다.
특징
- 캐시를 먼저 조회하기 때문에 캐시와 데이터베이스의 데이터 일관성이 깨질 수 있다. 이를 해결하기 위해서 일반적으로 *TTL(Time To Live)를 활용하여 특정 시간이 지나면 다시 DB에서 값을 조회하도록 하여 일관성을 맞춘다.
- 반복적인 읽기가 많은 서비스에 적합하다.
- 캐시에 장애가 발생하더라도 데이터베이스에서 데이터를 가져올 수 있어 서비스 운영은 가능하지만, 갑작스럽게 데이터베이스에 부하가 생길 수 있다. (*Thundering Herd)
* Thundering Herd
- 서비스 초기에 데이터가 없거나, 캐시에 데이터가 존재하다가 중간에 만료되어, 대량의 cache miss가 발생해서 갑작스럽게 데이터베이스에 트래픽이 몰려 부하가 생길 수 있다.
- 이를 방지하기 위해 *Cache Warming, 적절한 TTL 설정 그리고 캐시 조회 시 TTL을 확인하여, 얼마 남지 않은 경우 재할당하거나 하는 방어 로직을 추가할 수 있다.
* Cache Warming
- 캐시를 사전에 예열하는 과정이다.
- 시스템이 재시작 또는 배포 후 처음 시작될 때, 자주 접근되는 데이터는 아직 캐시에 로드되지 않아 초기 요청에서는 높은 대기 시간이 발생할 수 있습니다.
- 이러한 초기 대기 시간을 줄이기 위해, 시스템이 작동하기 전에 주요 데이터를 캐시에 미리 로드하는 것이다.
Read-Through
캐시에서만 데이터를 읽어오는 전략이다.
1. 캐시에 데이터가 있는지 확인한다.
2. 데이터가 캐싱되어 있으면, 즉시 클라이언트에게 해당 데이터를 제공한다. (cache hit)
3. 데이터가 캐싱되어 있지 않다면, 캐시가 데이터베이스에서 데이터를 읽어와 캐시에 저장한다. (cache miss)
4. 이후 클라이언트에게 응답한다.
특징
- Look-Aside와 비슷하지만, 서버가 캐시를 채우는 역할을 하느냐 마느냐에 따라 차이가 존재한다.
- Read-Though에서는 데이터 동기화 라이브러리나 캐싱 서비스 제공자에 의해 데이터베이스의 데이터를 저장한다.
- 데이터 동기화가 항상 이루어져 데이터 일관성은 맞지만, 전체적으로 조회 속도가 느리다.
- 데이터 조회 시 캐시에만 의존하기 때문에 캐시에 장애가 발생할 경우 서비스 이용에 문제가 생길 수 있다.
- 따라서 Replication 또는 Cluster 구성을 통해 가용성을 높여야 한다.
- 무조건 캐시에 저장하기 때문에 리소스 낭비가 발생할 수 있다. TTL을 사용하여 사용되지 않는 데이터는 삭제해야 한다.
Write-Back
캐시에 먼저 저장하고, 일정 주기 배치 작업을 통해 데이터베이스에 저장하는 전략이다.
1. 모든 데이터를 캐시에 저장한다.
2. 일정 시간이 지난 뒤에 데이터베이스에 저장한다.
특징
- 캐시에 데이터를 모았다가 일정 주기로 데이터베이스에 저장하기 때문에 데이터베이스 쓰기 부하를 줄일 수 있다.
- 하지만, 데이터를 저장하기 전에 캐시에 장애가 발생하면 데이터 유실이 발생할 수 있다.
- 쓰기 연산은 빈번하면서 읽기 연산을 하는데 많은 양의 리소스가 소모되는 서비스에 적합하다.
- 무조건 캐시에 저장하기 때문에 리소스 낭비가 발생할 수 있다. TTL을 사용하여 사용되지 않는 데이터는 삭제해야 한다.
Write-Through
데이터베이스와 캐시에 동시에 데이터를 저장하는 전략이다.
1. 저장할 데이터를 캐시에 먼저 저장한다.
2. 즉시 캐시에서 데이터베이스로 저장한다.
특징
- Read Through와 동일하게 데이터베이스와 데이터 동기화 작업을 캐시에게 위임한다.
- 데이터베이스와 캐시가 항상 동기화되어 있어, 캐시의 데이터는 항상 최신 상태로 유지된다.
- 매 요청마다 두 번의 쓰기 연산이 발생하게 되어, 쓰기 작업이 많은 서비스에는 부적합할 수 있다.
- 무조건 캐시에 저장학 때문에 리소스 낭비가 발생할 수 있다. TTL을 사용하여 사용되지 않는 데이터는 삭제해야 한다.
Write-Around
모든 데이터를 데이터베이스에 저장한다.
1. 모든 데이터를 데이터베이스에 저장한다. 캐시를 갱신하지 않는다.
특징
- 속도는 빠르지만, cache miss가 발생하기 전에 데이터베이스에 저장된 데이터가 수정되었을 경우 캐시와 데이터베이스 간의 데이터 불일치가 발생한다.
캐시 읽기 전략과 쓰기 전략의 조합
1) Look Aside + Write Around
읽기 : 캐시에서 읽고, 캐시에 없으면 데이터베이스에서 읽는다. (캐시 미스 시 캐시를 업데이트하지 않는다.)
쓰기 : 캐시를 건너뛰고 데이터베이스에 저장한다.
데이터 쓰기 시 캐시가 업데이트되지 않으므로 캐시에 저장하기에 적절하지 않거나 자주 사용하지 않는 데이터 저장을 방지할 수 있지만, 캐시 히트율이 낮아질 수 있다.
사용예시 : 데이터가 자주 조회되지만 쓰기 빈도가 낮은 시스템, 캐시의 중요 데이터만 저장하고 싶을 때
2) Read Trough + Write Around
읽기 : 캐시에서 읽고, 캐시에 없으면 데이터베이스에서 읽어 캐시에 업데이트한다.
쓰기 : 캐시를 건너뛰고 데이터베이스에 저장한다.
캐시 히트율이 높을 수 있지만, 데이터를 쓰고 나서 바로 읽으면 캐시 미스가 발생할 가능성이 있다.
사용 예시 : 읽기가 매우 빈번하고, 쓰기 후 즉시 데이터가 읽히지 않아도 괜찮은 경우
3) Read Though + Write Through
읽기 : 캐시에서 읽고, 캐시에 없으면 데이터베이스에서 읽어 캐시에 업데이트한다.
쓰기 : 캐시와 원본 데이터베이스에 동시에 저장
캐시와 데이터베이스 간의 데이터 정합성 이점과 최신 데이터 유지가 가능하지만, 쓰기 시 오버헤드가 발생한다.
사용 예시 : 쓰기 작업 후 즉시 최신 데이터가 필요로 하는 경우, 데이터 일관성이 중요한 경우
ex. 금융 서비스의 계좌 잔액 정보
참고
- 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#look_aside_+_write_around_%EC%A1%B0%ED%95%A9
- https://velog.io/@zenon8485/%EC%BA%90%EC%8B%B1%EC%A0%84%EB%9E%B5
- https://www.inflearn.com/course/redis-%EC%95%BC%EB%AC%B4%EC%A7%80%EA%B2%8C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-%EC%9D%B4%EB%A1%A0%ED%8E%B8/dashboard
'정리' 카테고리의 다른 글
분산 메시지 큐 이해하기: 가상 면접 사례로 배우는 대규모 시스템 설계 기초 2 (0) | 2024.11.04 |
---|---|
[Redis] redis.conf 기준 Redis 백업 방법 정리 (RDB vs AOF) (0) | 2024.10.28 |
[친절한 SQL 튜닝] NL 조인, 소트 머지 조인, 해시 조인 (2) | 2024.06.16 |
[친절한 SQL 튜닝] 인덱스 튜닝 (2) : 인덱스 스캔 효율화, 인덱스 설계 (0) | 2024.06.13 |
[친절한 SQL 튜닝] 인덱스 튜닝 (1) 테이블 액세스 최소화, 부분범위 처리 활용 (1) | 2024.05.05 |