Redis Copy-on-Write 분석

Redis Server Course Redis Technical Support Redis Enterprise Server

Redis Copy-on-Write 분석

개요 槪要 Outline

레디스 서버의 메모리 사용량은 실 데이터 크기에 관리 메모리(overhead)를 더해야 한다.   그리고 Copy-on-Write로 인한 추가 메모리를 고려해야 한다.   여기서는 Copy-on-Write에 대한 설명과 레디스에서 언제 Copy-on-Write가 발생하는지, 피하는 방법이 있는지, 추가로 필요한 메모리가 얼마인지에 대해서 알아보도록 한다.

Linux(Unix)에서는 자식 프로세스(child process)를 생성(fork)하면 같은 메모리 공간을 공유하게 된다.   그런데 부모 프로세스가 데이터를 새로 넣거나, 수정하거나, 지우게 되면 같은 메모리 공간을 공유할 수 없게 된다.   이때 부모 프로세스는 해당 페이지를 복사한 다음 수정한다.   이것을 Copy-on-Write(COW)라고 한다.
만약 자식 프로세스가 없었다면 페이지를 복사하지 않고 바로 수정했을 것이다.   따라서 자식 프로세스가 생성되어 작업을 하는 동안 데이터 입력/수정/삭제가 발생하면 해당 메모리 페이지를 복사해야 되기 때문에 평소보다 더 많은 메모리가 필요해진다.

Copy-on-Write 개념 槪念 Concepts

부모 프로세스가 자식 프로세스를 생성(fork)한 직후 프로세스와 메모리 모습
아래 그림은 "Operating System Concepts 9th edition(일명 공룡책)"을 참고했다.

Copy-on-Write after fork
    그림 1-1   자식 프로세스를 생성(fork)한 직후 프로세스와 메모리 모습

부모 프로세스가 Page C의 데이터를 수정하려면 우선 Page C를 복사(copy)한 다음 수정(write)한다.   리눅스는 4kB 페이지를 사용한다.   10 바이트만 수정해도 한 페이지(4kB)를 복사해야 한다.

Copy-on-Write After parent process modifies page C
    그림 1-2   부모 프로세스가 Page C를 수정한 후 프로세스와 메모리 모습

예를 들어, 1초에 1만 개의 데이터를 처리(입력/수정/삭제)하는 레디스 서버에 RDB background save가 발생해서 RDB 파일을 작성하는데 1분이 걸렸다고 하자.   그러면 60만 개의 데이터를 처리하는 것이고 데이터가 각각 다른 페이지에 들어갔다고 가정하면, 한 페이지가 4kB이므로 RDB background save가 진행되는 1분 동안 약 2.3gB의 메모리(RAM)이 추가로 필요하게 되는 것이다.
그러므로 Copy-on-Write가 발생하면 평소보다 많은 메모리가 필요한 것이다.

Copy-on-Write 언제 발생하나?

1.   save   파라미터

redis.conf 파일에 디폴트로 "save 60 10000" 이런 파라미터가 활성화(enable) 되어있다.   의미는 60초 동안 1만 개의 키가 새로 입력되면(바뀌면) RDB 파일을 새로 쓰라는 것이다.   이 파라미터로 RDB 파일을 새로 쓸 때 자식 프로세스가 생성되어 작업하는데 이때 COW가 발생한다.
예를 들어, 물리적 메모리가 32gB인 시스템에서 레디스 서버 인스턴스가 30gB를 사용하고 있었고, RDB 파일을 새로 쓰는 동안 COW가 발생해서 3gB의 메모리가 추가로 필요했다면, Real 메모리가 부족하므로 스왑(swap)이 발생해서 처리가 늦어져서 문제가 발생할 것이다.   그러므로 COW에 대비해서 여유 메모리가 필요하다.

2.   BGSAVE   명령

BGSAVE 명령을 수행하면 자식 프로세스가 생성되어 RDB 파일을 새로 쓴다.   이때도 똑같이 COW가 발생한다.   SAVE 명령은 레디스 프로세스가 직접 수행하므로 COW가 발생하지 않는다.

3.   복제 Replication

save 파라미터나 BGSAVE 명령을 실행하지 않아도 자신이 마스터이고 슬레이브가 연결되면, 전체 데이터 동기(full resync)가 발생하여 이때도 RDB 파일을 만들게 되므로 COW가 발생한다.   이것은 복제 시 RDB 파일을 디스크에 쓰지 않고 바로 소켓(네트워크)로 주는 옵션(repl-diskless-sync yes)을 사용해도 마찬가지다.   왜냐하면 대상(target)이 디스크인지 소켓인지만 다를 뿐 자식 프로세스가 생성되어 RDB 데이터를 만드는 것은 동일하기 때문이다.

4.   auto-aof-rewrite-percentage   파라미터

redis.conf 파일에 디폴트로 "auto-aof-rewrite-percentage 100" 이런 파라미터가 있다.   의미는 appendonly 파일이 100% 커지면 appendonly 파일을 다시 쓰라는 것이다.   다시 쓰기는 AOF 자식 프로세스가 생성되어 작업하는데, 이때도 COW가 발생한다.

5.   BGREWRITEAOF   명령

BGREWRITEAOF 명령을 수행하면 자식 프로세스가 생성되어 appendonly 파일을 다시 쓴다.   이때도 COW가 발생한다.

요약 Summary

COW는 위에서 설명한 다섯 가지 경우에 발생하며, 1,2,3번은 RDB 파일이고 4,5번은 AOF 파일 관련이다.   이제 회피 방법이 있는지 알아보자.

Copy-on-Write 회피 방법 回避 Avoid

  • RDB   save 파라미터: 사용하지 말 것을 권한다.   대신 AOF를 everysec로 사용한다.
  • RDB   BGSAVE 명령: 꼭 필요한 경우에만 서버 부하가 적을 때 사용한다.
  • RDB   복제: 새 슬레이브 연결은 부하가 적은 때를 이용한다.   기존 슬레이브에 문제가 생겨서 전체 데이터 복제(full resync)는 어쩔 수 없다.
  • AOF   auto-aof-rewrite-percentage 파라미터: 사용하지 말 것을 권한다.   즉 0으로 설정해서 disable 한다.   그럼, AOF 파일이 계속 커지는 것을 걱정할 것이다.   서버 부하가 적을 때 BGREWRITEAOF 명령을 수행해서 크기를 줄인다.   이에 대한 자세한 내용은 AOF Backup을 보세요.
  • AOF   BGREWRITEAOF 명령: 서버 부하가 적을 때 사용한다.   appendfsync everysec 설정과 관련하여 문제를 발생시키지 않는 방법은 AOF Backup을 보세요.

추가로 필요한 메모리는?

직접적으로 알아보는 방법

위에서 설명한 다섯 경우에 COW가 발생하면 모두 서버 로그에 얼마의 메모리를 사용했는지 남긴다.
RDB 관련 일 경우: "RDB: 256 MB of memory used by copy-on-write"
AOF 관련 일 경우: "AOF rewrite: 256 MB of memory used by copy-on-write"
로그에 있는 사용량을 보면 알 수 있다.   이 크기를 고려해서 여유 메모리를 정하자.

자식 프로세스는 어떻게 Copy-on-Write 량을 아는가?

리눅스의 /proc/[pid]/smaps(자기 자신의 process는 /proc/self/smaps 이다)에 보면 여러 가지 항목이 나오는데, 그중 Private_Dirty 항목이 COW이다.   레디스에서도 여러 영역에서 이 항목의 값을 합한 것을 보여주는 것이다.   이 경우는 heap 영역의 Private_Dirty 항목이 가장 크다.
아래 그림은 AOF rewrite 시 자식 프로세스의 smaps 파일을 켑처한 것이다.   heap 영역에서 Copy-on-Write가 8kB + 687316kB 발생한 것을 나타낸다.

Copy-on-Write smaps Private_Dirty
    그림 2   smaps 파일에서 Private_Dirty 항목

한 박스(머신)에 여러 인스턴스가 실행 중일 때

한 박스에 세 대의 레디스 인스턴스가 실행 중인 경우 동시에 RDB save가 발생해서 각 인스턴스당 COW로 3gB의 메모리가 추가로 필요하게 되면 총 9gB의 메모리가 필요하게 된다.   그러므로 COW가 자주 발생하지 않게 하는 것도 중요하다.   자동으로 COW가 발생하는 save, auto-aof-rewrite-percentage 파라미터의 활성화는 사용하지 않는 것이 좋다.   필요하면 각 인스턴스당 다른 시간에 실행할 수 있는 BGSAVE, BGREWRITEAOF 명령을 사용한다.   이렇게 잘 관리하면 세 대의 인스턴스가 있어도 3gB 메모리면 될 것이다.
한 인스턴스에서 RDB background save가 동시에 두 번 발생하거나, RDB background save 중 AOF rewrite가 발생하지 않도록 레디스 서버가 설계되어 있다.

그래서 추가로 필요한 메모리는?

운영 중이라면 로그를 보고 알아볼 수 있으나, 시작하는 단계라면 사용 메모리의 30%을 추가 메모리로 하자.   예를 들어, 사용 메모리를 12gB로 추정(측정)했다면 3.6gB를 추가 메모리로 계산해서 인스턴스당 15.6gB로 계산해서 서버 메모리를 정하면 부족하지 않을 것이다.  

정리 整理 Summary

Copy-on-Write의 개념과 언제 발생하는지, 피하는 방법, 추가 메모리에 대해서 알아보았습니다. COW로 인한 추가 메모리를 고려해서 서버를 도입하시기 바랍니다.
다음 페이지에서는 한 머신에 여러 레디스 인스턴스를 수행할 때 메모리 량과 SSD의 용도, 크기 그리고 HDD에 대해서 알아보겠습니다.


<< Server Main Memory Copy-on-Write Server Specification >>

조회수 :

Email 답글이 올라오면 이메일로 알려드리겠습니다.