티스토리 뷰
1. Redis 메모리 사용량 추정하기(Redis Memory Usage Estimation)
[ 사전 지식 습득하기 ]
레퍼럴에 대하여
이번에 레디스 메모리 사용량을 분석할 서비스는 다음과 같은 초대 이벤트 서비스이다. 친구들에게 나의 초대키를 공유하여 친구가 접속하면 나에게 혜택을 받는 구조인데, 이를 레퍼럴(Referral)이라고 한다. 일종의 추천인 제도라고 볼 수 있는데, 흔히 사용되는 마케팅 기법 중 하나이다. 이러한 마케팅 기법에는 때 크게 공유자와 피공유자라는 두 종류의 액터가 등장하는데, 이러한 내용을 바탕으로 레디스에 저장되는 메모리 사용량을 추산해보도록 하자. 참고로 이번 이벤트의 참여자는 500만명으로 가정한다.
레디스 오버헤드를 포함한 사용량 공식 도출
다른 모든 시스템과 마찬가지로 레디스 역시 데이터 관리를 위한 오버헤드(overhead) 메모리가 필요하다. 각각의 데이터 타입 별로 오버헤드는 다음과 같다고 한다. 참고로 이는 레디스 3.2.2를 기준으로 하는데, 최신의 레디스는 6/7 정도에 해당하므로 이를 유의하도록 하자.
- Key: 50 bytes
- Strings: 30 bytes
- Lists: 15 bytes
- Sets: 75 bytes
- ZSets: 120 bytes
- Hashes: 100 bytes
따라서 이러한 부분을 고려하여 메모리 사용량 공식을 다음과 같이 잡을 수 있다. gzip 압축의 경우 평균적으로 압축을 통해 약 70%의 메모리 만을 사용한다고 가정한다.
(key 오버헤드 + key 데이터 + value 오버헤드 + value 데이터 사용량 * 0.7 * value의 수) * 사용자의 수
[ 메모리 사용량 추산하기 ]
나의 피초대키 목록
이번에 제작하는 서비스에서는 내가 최대 3개의 초대 코드를 관리할 수 있다고 하자. 따라서 우리가 저장하는 데이터 구조는 다음과 같은 형태가 될 것이다.
- key
- promotion:friend-invitation:invitees:{userId}
- value
- Set 자료 구조를 사용하며, 문자열 데이터를 저장함
- ex) [V02HdsTDj, ZdAG123aB, N23AaCPd]
이러한 내용을 바탕으로 사용량을 추산해보면, 다음과 같은 사용량을 예측할 수 있다.
- key 사용량: 46bytes
- key 관리 오버헤드: 50bytes
- value 사용량: 9bytes * 3 = 27bytes
- value 관리 오버헤드: 75bytes
따라서 전체 사용량을 계산하여 다음과 같은 사용량을 추산할 수 있다.
(46 + 50 + 9 * 0.7 * 3 + 75) * 5000000 = 약 949.5 MB
나의 피초대 리워드
내가 피초대로 사람을 불러올 경우, 받을 리워드 금액을 저장한다. 리워드는 단순 Long 타입만 저장하면 되므로 데이터 구조는 다음과 같은 형태가 될 것이다.
- key
- promotion:friend-invitation:reward:{userId}
- value
- 레디스에서는 Long 타입 역시 String으로 관리됨
- ex) “10000”
이러한 내용을 바탕으로 사용량을 추산해보면, 다음과 같은 사용량을 예측할 수 있다.
- key 사용량: 46bytes
- key 관리 오버헤드: 50bytes
- value 사용량: 5ytes
- value 관리 오버헤드: 30bytes
따라서 전체 사용량을 계산하여 다음과 같은 사용량을 추산할 수 있다.
(46 + 50 + 5 * 0.7 + 30) * 5000000 = 약 647 MB
나의 초대 코드 정보
본인의 초대 코드 생성 정보는 다음과 같은 객체로 저장되며, 레디스에 저장할 때는 단순 문자열로 저장된다고 볼 수 있다.
- key
- promotion:friend-invitation:referral:{userId}
- value
- 별도로 구성하는 초대자 클래스의 객체를 관리함
이때 피초대자 클래스는 다음과 같이 구성된다고 하자.
class Referral(
val id: Long,
val promotionKey: Long,
val referralKey: String,
val userId: Long,
val userKey: Long,
val amount: Long,
val createdAt: LocalDateTime,
)
현재 사용중인 레디스 설정으로는 객체를 json 문자열로 저장하고 있기 때문에, 문자열 길이를 측정해야 한다. 측정 결과에 따르면 약 160 bytes 정도를 사용중인 것을 확인하였다. 이러한 내용을 바탕으로 사용량을 추산해보면, 다음과 같은 사용량을 예측할 수 있다.
- key 사용량: 41 bytes
- key 관리 오버헤드: 50 bytes
- value 사용량: 160 bytes
- value 관리 오버헤드: 30 bytes
따라서 전체 사용량을 계산하여 다음과 같은 사용량을 추산할 수 있다.
(41 + 50 + 160 * 0.7 + 30) * 5000000 = 약 1165 MB
나의 피초대자 목록
본인의 피초대 코드로 가입한 피초대자 목록을 List로 저장하며, List에는 최대 15개의 객체가 저장될 수 있다고 하자. 그러면 key-value는 다음과 같이 구성할 수 있다.
- key
- promotion:friend-invitation:invitees:{referralKey}
- value
- 별도로 구성하는 피초대자 클래스의 객체를 List로 관리함
이때 피초대자 클래스는 다음과 같이 구성된다고 하자.
class Invitee(
val id: Long,
val promotionKey: String,
val referralKey: String,
val userId: Long,
val key: Long,
val reward: Long,
val expiredAt: LocalDateTime?,
var status: InviteeStatus,
var updatedAt: LocalDateTime,
var createdAt: LocalDateTime,
)
마찬가지로 해당 객체 1개가 갖는 문자열의 크기를 계산해보면 약 260 bytes에 해당하며, 이러한 내용을 바탕으로 사용량을 추산해보면, 다음과 같은 사용량을 예측할 수 있다.
- key 사용량: 41 bytes
- key 관리 오버헤드: 50 bytes
- value 사용량: 260 bytes
- value 관리 오버헤드: 15 bytes
따라서 전체 사용량을 계산하여 다음과 같은 사용량을 추산할 수 있다.
(41 + 50 + 260 * 0.7 * 15 + 15) * 5000000 = 약 14180 MB
나의 리워드 지급 목록
마지막으로 본인의 리워드 지급 역시 관리되어야 하는데, 해당 목록 역시 List로 저장하며, 당장은 최대 1개의 객체가 저장될 수 있다고 하자. 그러면 key-value는 다음과 같이 구성할 수 있다.
- key
- promotion:friend-invitation:rewards:{userId}
- value
- 별도로 구성하는 피초대자 클래스의 객체를 List로 관리함
이때 피초대자 클래스는 다음과 같이 구성된다고 하자.
class RewardHistory(
val id: Long,
var rewardType: RewardHistoryType,
var amount: Long,
val brandcon: Long?,
val promotionNo: Int,
val promotionKey: String,
var userKey: Long,
var txNo: Long?,
var rewardStatus: RewardHistoryStatus,
var paidAt: LocalDateTime?,
val createdAt: LocalDateTime,
var updatedAt: LocalDateTime,
)
마찬가지로 해당 객체 1개에 해당하는 문자열이 갖는 메모리 사용량을 추산하면 300 bytes로, 다음과 같은 사용량을 예측할 수 있다.
- key 사용량: 41 bytes
- key 관리 오버헤드: 50 bytes
- value 사용량: 300 bytes
- value 관리 오버헤드: 15 bytes
따라서 전체 사용량을 계산하여 다음과 같은 사용량을 추산할 수 있다.
(41 + 50 + 300 * 0.7 * 1 + 15) * 5000000 = 약 1580 MB
[ 전체 메모리 사용량 ]
- 나의 피초대키 목록: 949.5 MB
- 나의 피초대 리워드: 647 MB
- 나의 초대 코드 정보: 1165 MB
- 나의 피초대자 목록: 14180 MB
- 나의 리워드 지급 목록: 1580 MB
위의 내용을 바탕으로 전체 사용량은 약 18421.5 MB으로, 약 18.5 GB의 용량이 사용된다고 볼 수 있다. 참고로 이는 순수 데이터 용량에만 해당하며, 실제로는 레디스 운영을 위해 필요한 각종 오버헤드(startup, slave replication, cow) 용량들이 추가로 필요하다. 따라서 이러한 부분을 고려하여 넉넉하게 용량을 산정할 필요가 있을 것이다.
참고로 위의 산정 결과를 바탕으로, 실제 참여자 수와 참여 데이터 수에 비례하여 데이터를 산정해보면 약 1~2 GB 정도의 오차 밖에 존재하지 않았음을 확인할 수 있었다. 따라서 레디스 용량 산정을 위한 기준점으로 삼기에는 충분할 것으로 보인다.
참고 자료
- http://redisgate.kr/redis/server/memory.php
- http://redisgate.kr/redis/configuration/server_memory.php
- http://redisgate.kr/redis/configuration/copy-on-write.php
'Server' 카테고리의 다른 글
[Server] 데이터 중심의 세상과 객체 지향 프로그래밍(Data-Oriented and Object-Oriented Programming) (2) | 2024.11.12 |
---|---|
[Server] 객체에게 역할과 책임을 부여하는 객체 지향 프로그래밍(Object-Oriented Programming) (3) | 2024.11.05 |
[Server] 진짜 중복과 가짜 중복의 구분(중복 여부를 판단하는 기준) (4) | 2024.10.22 |
[Server] 비즈니스 정책과 입력 데이터, 서로 다른 데이터 검증 및 유효성 검사(Validation) (7) | 2024.10.01 |
[Server] Redis와 LuaScript(레디스와 루아스크립트)를 활용한 슬라이딩 윈도우 구현하기 (0) | 2024.05.07 |