Database/Redis

[Redis] Key 관리를 통해 메모리를 효율적으로 사용하는 방법

꽁담 2021. 1. 8. 00:53

개요


서비스에서 380만 정도 Key에 21GB 정도의 메모리가 할당되어 운영되고 있습니다.

 

메모리 DB 라는 관점에서, 21GB 라는 메모리는 큰 편이라고 볼 순 없지만

AWS EC2 환경에서 r5.2xlarge 타입으로 운영되고 있고 Scale Up 을 하는순간 추가 비용이 발생하는 문제와

디스크처럼 여유롭게 공간을 확보하기 힘들기 때문에 개선이 필요할 것으로 보았습니다.

 

 

개선방법


포스팅에서 다루지 않을 개선 방법

가장 편한 방법은 필요없는 데이터를 삭제하는 것과 위에서 말한것처럼 Scale Up 을 하는 것 입니다.

( 사실 라이브 상황에서 이건 쉬운 방법이 아닙니다.. ㅠㅠ )

 

Scale Up 을 하는동안의 DownTime 을 감당해야 하고 (이중화로 구성되어 있기 때문에 서비스 다운은 아니지만요.)

필요없는 데이터를 추려 삭제하는 방법또한 시간이 소요됩니다.

 

포스팅에서 다룰 개선 방법

또하나의 방법은 데이터 저장을 메모리를 낭비하면서 하고 있진 않는지 확인해 보는 방법입니다.

확인을 위해서는 Key 가 어떻게 저장이 되고 있는지 알아야 하고,

OverHead 는 얼마나 발생하는지를 알아야 합니다.

 

아래에서 정리해보겠습니다.

참고로 이 방법도 만만치는 않습니다. 구조 개선은 개발 코드도 뜯어 고쳐야 하기 때문입니다.

 

 

키와 데이터타입의 오버헤드 비용


레디스에서는 Key 와 DataType 을 관리하기 위한 OverHead 가 발생합니다.

제가 직접 계산해본 것은 아니지만 RedisGate 사이트에 따르면 아래와 같이 나와있습니다.

 

* 레디스 버전마다 다르기 때문에 이에 대한 부분은 정확하지 않을 수 있습니다.

- 키의 관리 메모리 : 50 바이트

- String 타입의 관리 메모리 : 30 바이트

- Lists 타입의 관리 메모리 : 15 바이트

- Sets 타입의 관리 메모리 : 75 바이트

- ZSets 타입의 관리 메모리 : 120 바이트

- Hash 타입의 관리 메모리 : 100 바이트

 

redisgate.kr/redis/configuration/server_memory.php

 

데이터 타입에 따른 레디스 사용 메모리를 간략하게 비교하기 위해 타입에 대해 먼저 설명하면

String 은 데이터 저장할때마다 키의 관리 메모리가 들어가지만

Hash 는 같은 Key 내에 Fileds 로 구분하여 데이터를 저장하기 때문에 하나의 키 관리 비용만 들어가게 할 수 있습니다.

 

 

테스트


레디스 버전 : 2.8.4

 

임시 테스트

최초 키가 적재될 때는 used_memory 가 동일했지만,

데이터를 넣을수록 used_memory 가 String 이 올라가는 것을 볼 수 있습니다.

String 타입 Hash 타입
info memory
# Memory
used_memory:500248
info memory
# Memory
used_memory:500248
set Key0 "Dummy Data" hset K0 Key0 "Dummy Data"
500344info memory
# Memory
used_memory:500344
info memory
# Memory
used_memory:500344
set Key1 "Dummy Data" hset K0 Key1 "Dummy Data"
info memory
# Memory
used_memory:500440
info memory
# Memory
used_memory:500360
set Key2 "Dummy Data" hset K0 Key2 "Dummy Data"
info memory
# Memory
used_memory:500536
info memory
# Memory
used_memory:500392

 

본격적인 테스트

키의 갯수를 좀 더 늘려봅니다.

이번에는 스크립트를 통해서 테스트 건수를 정하면서 진행해 보도록 하겠습니다.

 

스크립트는 다음과 같고  필요하신 분은 가져다 쓰셔도 되고, 레디스 접속하는 부분만 수정해 주시면 됩니다.

다른 타입으로 테스트가 필요하시는 분은  레디스 적재하는 부분에서 저장방식만 변경하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
$ cat key.sh
test_cnt=100000
dummy="THIS IS DUMMY DATA FOR TEST."
 
echo "String Type"  > result.txt
echo "============" >> result.txt
echo "before"       >> result.txt
echo "info memory"  >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
i=0
while [ 1 = 1 ]
do
    i=`expr $i + 1`
    redis-cli -6161 -a P@ssword set $i "$dummy"  > /dev/null 2>&1
    if [ $i = $test_cnt ]
    then
        break
    fi
done
 
echo "============" >> result.txt
echo "after" >> result.txt
echo "info memory" >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
i=0
while [ 1 = 1 ]
do
    i=`expr $i + 1`
    redis-cli -6161 -a P@ssword del $i > /dev/null 2>&1
    if [ $i = $test_cnt ]
    then
        break
    fi
done
echo "============" >> result.txt
echo "finish" >> result.txt
echo "info memory" >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
###############################################################################################################
 
echo "" >> result.txt
echo "" >> result.txt
echo "" >> result.txt
echo "hSet Type" >> result.txt
echo "============" >> result.txt
echo "before" >> result.txt
echo "info memory" >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
i=0
j=0
k=0
while [ 1 = 1 ]
do
        i=`expr $i + 1`
        j=`expr $i % 1000`
 
    redis-cli -6161 -a P@ssword hset $k $i "$dummy"  > /dev/null 2>&1
        if [ $j = 0 ]
        then
             k=`expr $k + 1`
        fi
 
        if [ $i = $test_cnt ]
        then
                break
        fi
done
 
echo "============" >> result.txt
echo "after" >> result.txt
echo "info memory" >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
i=0
j=0
k=0
while [ 1 = 1 ]
do
        i=`expr $i + 1`
        j=`expr $i % 1000`
    redis-cli -6161 -a P@ssword hdel $k $i > /dev/null 2>&1
        if [ $j = 0 ]
        then
             k=`expr $k + 1`
        fi
 
    if [ $i = $test_cnt ]
    then
        break
   fi
done
 
echo "============" >> result.txt
echo "finish" >> result.txt
echo "info memory" >> result.txt
redis-cli -6161 -a P@ssword info memory >> result.txt
echo "info keyspace" >> result.txt
redis-cli -6161 -a P@ssword info keyspace >> result.txt
echo "============" >> result.txt
 
cs

 

테스트 결과

test_cnt 가 1,000 일 때

- String 타입 : Key 1,000 개

- Hash 타입 : Key 1 개 / Fields 1,000 개

결과 : 2.6 % 정도의 메모리 개선 효과

    테스트 전 테스트 후 키 정리 후
String Used Memory (byte) 500,248 620,408 500,248
Keys 0 1,000 0
Hash Used Memory (byte) 500,248 604,600 500,248
Keys 0 1 0

 

test_cnt 가 100,000 일 때

- String 타입 : Key 100,000 개

- Hash 타입 : Key 100 개 / Fields 1,000 개

결과 : 2.6% 정도의 메모리 개선 효과

    테스트 전 테스트 후 키 정리 후
String Used Memory (byte) 500,248 12,748,792 502,264
Keys 0 100,000 0
Hash Used Memory (byte) 502,264 12,376,456 502,248
Keys 0 100 0

 

 

결론


String 과 Hash 타입의 저장에 따른 메모리 사용률 비교 결과

Hash 타입이 String 보다 2.6% 정도의 메모리 개선 효과가 나타났습니다.

 

생각하는 것만큼 확.. 와닿지는 않아서 아쉬웠습니다만 ㅠㅠ

레디스 사이즈가 커질수록 저장공간 확보도 클 것이고 (예를들면,, 1TB 면 30 GByte 확보가능)

그래도 타입에 따른 메모리 개선을 할 수 있다는 점에서는 소득이 있었던 것으로 보입니다.

 

추가로, 오버헤드 비용은 레디스 버전마다 다른 것으로 알고 있습니다.

버전에 따라 개선의 폭이 클 수도 있기에 데이터 타입 테스트를 진행해 보는것을 추천드립니다.

 

 

 

 

 

 

 

 

레디스 데이터 타입 오버헤드

레디스 메모리 사용량

레디스 메모리 최적화

레디스 메모리 효율적으로