탄생 배경
Redis는 메모리 기반의 캐시저장소로, Spring에서는 Spring Cache를 도입해서 읽기 작업의 성능을 높이는 작업을 수행할 수 있다.
하지만 메모리라는 한정된 자원에서 데이터가 계속해서 쌓이다 보면 Redis는 새로운 데이터를 저장하기 위해 기존 데이터를 삭제해야 하는 문제에 봉착하게 된다. 아니면 애플리케이션 성능에 문제를 일으킬 수도 있다.
Redis의 메모리 관리 방법
Redis는 RAM의 용량보다 더 많은 데이터를 저장하게 되는 경우 Swap이 발생하며 Redis의 성능 저하를 일으킬 수 있다.
물리 메모리의 용량보다 더 많은 데이터가 들어오면 swap이 발생한다.
운영체제에서 Swap space의 주요 기능은 물리메모리(RAM)의 양이 가득 차고 더 많은 메모리의 양이 필요할 때 Backing store(디스크)의 가상메모리에 대체한다.
그렇기에 보통 스왑영역을 사용하지 않기 위해 MAX Memory
를 별도로 지정해준다.
해당 설정은 redis.conf 파일의 maxmemory 옵션을 지정해주면 된다.
이러한 메모리 관리 방법을 통해 데이터를 최대치로 저장할 시 기존의 데이터는 제거되고 새로운 데이터가 저장되게 된다.
이것을 Eviction
이라고 부르며, 이러한 방식을 만들기 위해 “maxmemory-policy” 옵션을 통해 Eviction 정책을 만들 수 있다.
Eviction Policy
1. noeviction
- 새 데이터를 저장해야할 때 메모리가 부족하면 오류를 반환(OOM command Not allowed)하고, 기존 키는 절대 삭제하지 않는다.
- 캐시보다는 데이터의 무결성이 중요한 경우에 사용된다.
2. allkeys-Iru
- 모든 키를 대상으로 LRU 알고리즘 적용
- 최근에 사용되지 않는 키를 우선적 제거
3. volatile-lru
- 만료시간이 설정된 키들을 대상으로 LRU 적용
- 만료 설정(ttl)이 없는 경우 키 삭제 X
4. allkeys-random
- 모든 키 중 무작위로 제거
- LRU 알고리즘 계산의 오버헤드를 피하고 단순 무작위 접근으로 해결
5. allkeys-lfu
- 새로 추가된 데이터의 용량을 확보하기 위해 사용빈도수가 가장 적은 키를 제거(최근 저장된 키라도 사용 빈도수가 적다면 대상이 될 수 있다.)
6. volatile-lfu
- 새로 추가된 데이터의 용량을 확보하기 위해 TTL이 설정된 키들 중 사용빈도 수가 적은 키를 제거 (최근 저장된 키라도 사용 빈도수가 적다면 대상이 될 수 있다.)
7. volatile-random
- 새로 추가된 데이터의 용량을 확보하기 위해 TTL이 설정된 키들 중 무작위로 키를 제거
8. volatile-ttl
- 새로 추가된 데이터의 용량을 확보하기 위해 TTL이 짧은 키를 제거
내가 Redis를 사용한 프로젝트에서의 정책
우선 실시간 음원 스트리밍 플랫폼인 ‘WhatSong(이하 왓송)’의 경우 noeviction 과 volatile- 정책들은 적합하지 않았다.
우선 Redis를 어디에 활용했는가?
음원을 스트리밍 중에 대한 방에 대한 정보 데이터들을 담기 위해 Redis를 활용했다
이 방에 대한 정보에는 아래와 같은 데이터가 포함된다.(설명을 위해 필드명 등 간략화)
public class MusicRoomPlay{
private String musicId; // youtube Id
private List<MemberDTO> members = new ArrayList<>(); // 현재 방에 참가한 인원정보
...
}
위 데이터는 음악 대기열 상태를 관리하고 현재 재생될 음악에 대한 정보를 Client에게 전달하는 모델로 활용했다.
추가적으로 왓송의 경우 음원 방의 방장(Admin User)만이 음악을 대기열에 추가할 수 있고 일반 유저의 경우 음악 요청을 추가하고 이를 방장이 승인해야지 대기열에 추가되는 구조이다.
엥 그럼 volatile- 정책이 적합할거 같은데요? 어차피 소모되는 데이터 잖아요?
나 또한 이렇게 생각을 했고 각 음원 데이터에 대한 ttl(time-to-live)
을 여유롭게 설정하면 캐시 메모리를 효율적으로 관리할 수 있을 것이라 판단했다.
하지만, 당시 스트리밍 전략을 위해 Youtube Open API를 활용하고 있었는데, Youtube의 음원 데이터만을 따로 필터링하여 추출하는 것은 정책에 위반되었기에 일반 영상 또한 포함될 수 밖에 없었다.
그렇기에 영상길이를 규제할 수 없었고 volatile 정책을 활용할 수 없었다.
그렇기에 나는 allkeys-lru
정책을 선택하였다.
플레이리스트의 경우 순차적으로 재생되기에 이전곡을 참조할 수도 있지만 오래된 이전 곡은 지우는 방식을 구현하기위해 이를 선택하였다.
💡 이처럼 프로젝트의 특성에 맞추어 Redis Eviction 정책을 활용하여서 리소스에 대한 관리를 효율적으로 이뤄내야한다고 생각한다.
'Tech-Interview' 카테고리의 다른 글
사용자 증가에 따른 서버확장 (0) | 2024.12.08 |
---|---|
JPA ID 생성전략 (0) | 2024.12.06 |
JPA N+1 문제 (0) | 2024.11.28 |
리터럴 String과 new String()의 차이 (0) | 2024.11.13 |
Docker와 컨테이너 (0) | 2024.11.04 |