개요
레디스는 메모리DB 입니다.
메모리DB 이기 때문에 레디스에서 사용하는 메모리 할당량을 확실히 알아야 합니다.
메모리가 부족하게 되면 OOM 에 의해 프로세스가 죽을 수 있기 때문입니다.
그래서 메모리 사용량에 대해 조사하던 도중
SAVE 동작 시 자식프로세스가 생성되어 rdb 파일을 백업하는 데 이 때 메모리를 2배로 사용한다.
라는 글이 있어서 이에 대한 테스트를 진행해 보려고 합니다.
메모리를 2배로 사용한다는 의미는 아래와 같습니다.
레디스 프로세스 (부모) 가 메모리상의 데이터를 가지고 있고,
SAVE 시 자식 프로세스가 생성되어 메모리상의 데이터를 전체 복사 후 rdb 파일로 내려쓴다.
참고로 이 포스팅에서의 SAVE 동작은 사용자가 직접하는게 아니라
레디스 엔진에서 save 옵션값으로 인해 진행되거나 혹은 사용자가 BGSAVE 를 하는 걸 의미합니다.
정확한 SAVE 시 메모리 사용량에 대한 정리
만약 SAVE 시 자식 프로세스가 무조건 메모리를 부모프로세스만큼 사용한다 라고 한다면
부모프로세스가 사용하는 메모리 크기보다, 메모리 Free 량이 작은경우 장애가 발생할 것입니다.
예를들면 레디스 프로세스가 500MB 의 메모리를 할당받아 사용하는데
메모리 Free 량이 100MB 라면, 자식 프로세스는 500MB 의 메모리를 할당받을 수 없기 때문입니다.
위와 유사한 환경을 만든 후에 save 를 진행해 봅니다.
환경
레디스에서 사용하는 메모리는 369,050,984 byte 입니다.
전체 메모리에서 현재 사용하는 메모리를 빼면 남은 메모리는 193,380,352 byte 입니다.
위의 무조건 2배를 사용한다는 말이 성립되려면,
메모리 부족으로 인해 save 작업이 실패하거나 부모프로세스가 죽거나 둘 중 하나가 되어야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$ redis-cli -p 6161 -a P@ssword
127.0.0.1:6161> info memory
# Memory
used_memory:369050984
$ free -b
total used free shared buff/cache available
Mem: 1414692864 1221312512 63930368 33636352 129449984 37371904
스왑: 0 0 0
$ expr 1414692864 - 1221312512
193380352
|
cs |
결과는 어땠을까요?
SAVE 작업은 정상적으로 되었고,
로그파일 7번째 라인을 보면 COW 로 인한 메모리는 0MB 를 사용했다고 나왔습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
127.0.0.1:6161> bgsave
Background saving started
$ tail -f redis_6161.log
[1729] 08 Jan 23:36:33.466 * Background saving started by pid 2097
[2097] 08 Jan 23:36:36.580 * DB saved on disk
[2097] 08 Jan 23:36:36.915 * RDB: 0 MB of memory used by copy-on-write
[1729] 08 Jan 23:36:36.995 * Background saving terminated with success
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2157 psh 20 0 421612 369000 1008 D 90.0 26.7 0:02.80 redis-rdb-bgsave *:6161
1729 psh 20 0 421216 368768 908 S 0.0 26.7 0:05.47 redis-server *:6161
1310 psh 20 0 4698564 259340 37956 S 2.7 18.8 0:30.89 /usr/bin/gnome-shell
1742 psh 20 0 1380684 98116 856 S 0.0 7.1 0:03.41 /usr/bin/gnome-software --gapplication-se+
|
cs |
만약 데이터 쓰기작업이 들어오는 상황에서 SAVE 가 발생하면 어떻게 될까요?
COW 에 의해 23MB 의 메모리가 사용되었다는 로그메시지가 기록됩니다.
1
2
3
4
5
|
[1729] 08 Jan 23:51:42.289 * Background saving started by pid 9941
[9941] 08 Jan 23:51:46.204 * DB saved on disk
[9941] 08 Jan 23:51:46.458 * RDB: 23 MB of memory used by copy-on-write
[1729] 08 Jan 23:51:46.571 * Background saving terminated with success
|
cs |
정리하면
위에서 테스트를 한 결과로 보다시피
SAVE 작업이 일어날 때 자식프로세스는 무조건 2배를 사용한다는 말은 아닙니다.
그럼 어떻게 동작을 할까요?
Save 작업 시 자식프로세스 동작 구조
1. SAVE 가 수행되면 부모프로세스는 자식프로세스를 fork 합니다.
2. 자식프로세스는 부모프로세스가 가지고 있는 메모리를 완전 공유합니다.
즉, 자식프로세스가 별도로 사용하는 메모리는 없습니다.
3. 자식프로세스는 이렇게 공유한 메모리를 temp- 명으로 시작되는 rdb 파일로 쓰기 시작합니다.
4. 자식프로세스가 쓰기작업을 완료하면 rdb 파일을 교체한 후 프로세스를 종료합니다.
그런데 SAVE 를 하는 도중 메모리에 쓰기작업이 발생할 가능성은 얼마든지 있습니다.
이럴때는 어떻게 동작할까요? 위의 단계에서 이어서 설명하도록 하겠습니다.
Save 작업 시 메모리 쓰기작업이 발생하는 경우 동작 구조
3. 자식프로세스는 이렇게 공유한 메모리를 temp- 명으로 시작되는 rdb 파일로 쓰기 시작합니다.
4. 메모리에 쓰기작업이 발생하였습니다.
5. 부모프로세스는 쓰기작업이 발생하는 페이지를 먼저 복사한 후 수정합니다. ( Copy-on-Write 방식 )
6. 자식프로세스는 기존의 페이지를 계속 백업합니다.
7. 자식프로세스가 쓰기작업을 완료하면 rdb 파일을 교체한 후 프로세스를 종료한다.
8. 부모프로세스는 이전 데이터를 가지는 페이지를 정리합니다.
로그 메시지에서 아래 내용은 RDB 를 진행하는 도중
copy-on-write 에 의해 23MB 의 메모리가 더 사용이 되었다 라는 것을 의미합니다.
1
|
[9941] 08 Jan 23:51:46.458 * RDB: 23 MB of memory used by copy-on-write
|
cs |
결과적으로 위에서 작성한 환경에서 SAVE 가 진행되는 동안
부모와 자식프로세스가 사용한 메모리는 총 351MB + 23MB 입니다.
결론
SAVE 동작시 메모리를 무조건 2배로 사용한다 라는 것은 아닌 것으로 확인되었습니다.
그러나 2배를 사용할 수도 있습니다.
SAVE 가 진행되는 동안 메모리의 모든 페이지가 쓰기작업이 발생된다면 말이죠..
가장 안심하고 운영할 수 있는 환경은 메모리 사용률을 50% 이하로 낮춰놓는 방법입니다.
그러면 레디스에서 사용하는 메모리는 50% 보다 아래일 것이고, (운영체제 + 일반 프로세스가 사용하는 메모리 제외)
SAVE 작업시 모든 메모리 쓰기작업이 발생해도 메모리 사용률이 100% 는 되지 않을 것이기 때문입니다.
그렇지만 캐시용도로 사용되는 서버이면서 (원천 데이터는 다른 서버에 있음)
쓰기작업보단 읽기작업이 빈번하게 발생하는 용도라면 메모리 사용률을 60% 혹은 70% 까지 올려도 문제는 없을 것으로 보입니다.
메모리 사용률 알람을 무조건 50% 이하보다는
운영하면서 save 작업 시 Copy-On-Write 가 얼마나 발생하는지 계산한 후에
메모리 사용률의 임계치를 설정하는 것이 좋을 것 같습니다.
레디스 SAVE 메모리 사용률
레디스 메모리 임계치
레디스 자식프로세스 메모리 사용률
'Database > Redis' 카테고리의 다른 글
[Redis] jemalloc No such file or directory 오류 해결하기 (0) | 2021.03.08 |
---|---|
[Redis] Asynchronous AOF fsync is taking too long (disk is busy?). 오류 (0) | 2021.03.07 |
[Redis] Key 관리를 통해 메모리를 효율적으로 사용하는 방법 (0) | 2021.01.08 |
[Redis] Jedis 에서 Sentinel 의 pub/sub 을 제대로 인지할까? (0) | 2020.12.27 |
[Redis] Jedis 에서 Redis Sentinel 을 통한 마스터 정보 얻는 방법 (0) | 2020.12.23 |