[입 개발] Redis의 mem_fragmentation_ratio 는 어떻게 구할까?

요새 Redis Issue를 보면 메모리를 쓰고 나도 계속 mem_fragmentation_ratio 와 used_memory_rss 값이 여전히 높다라는 글이 자주 올라옵니다. 실제로 제목은 mem_fragmentation_ratio 를 구하는 방법이지만, mem_fragmentation_ratio 는 다음과 같이 간단하게 구해집니다.(Info Command를 통해서 redis에서 확인가능합니다.)


mem_fragmentation_ratio = used_memory_rss / zmalloc_used_memory

코드를 보면 다음과 같습니다.


/* Fragmentation = RSS / allocated-bytes */

float zmalloc_get_fragmentation_ratio(void) {
 return (float)zmalloc_get_rss()/zmalloc_used_memory();
}

그렇다면 사실 핵심은 zmalloc_get_rss를 어떻게 구하는가가 핵심이라는 걸 알게됩니다.
rss 값을 구하는 것은 여러가지 정책이 있는데 proc 를 제공해주는 곳에서는 /proc/{pid}/stat 값을 읽어서 해당 값을 알 수 있습니다. 24번째 값이 RSS 의 페이지 개수입니다. TASK_INFO를 제공해주는 곳에서는 해당 함수를 이용해서 rss 값을 구하고, 이도 저도 없는 플랫폼은 그냥 zmalloc_used_memory를 리턴합니다.(이때는 무조건 ratio 가 1이 되겠죠?)

코드는 zmalloc.c에 존재하고 리눅스에서 proc를 읽어서 처리하는 것은 다음과 같습니다. 코드는 워낙 간단해서 다른 설명은 없습니다. 핵심은 rss 값을 읽어오는 것과, sysconf 를 PAGESIZE를 가져옵니다. rss 가 페이지 개수이므로 여기에 PAGESIZE를 곱하면 실제 사용하고 있는 총 메모리 양이 나옵니다.(OS가 페이지 단위로 메모리를 할당하므로 ㅎㅎㅎ 이게 실제 사용량이 됩니다.)

size_t zmalloc_get_rss(void) {
 int page = sysconf(_SC_PAGESIZE);
 size_t rss;
 char buf[4096];
 char filename[256];
 int fd, count;
 char *p, *x;

snprintf(filename,256,"/proc/%d/stat",getpid());
 if ((fd = open(filename,O_RDONLY)) == -1) return 0;
 if (read(fd,buf,4096) <= 0) {
 close(fd);
 return 0;
 }

close(fd);

p = buf;
 count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
 while(p && count--) {
 p = strchr(p,' ');
 if (p) p++;
 }
 if (!p) return 0;
 x = strchr(p,' ');
 if (!x) return 0;
 *x = '\0';

rss = strtoll(p,NULL,10);
 rss *= page;
 return rss;
}

/proc/{pid}/stat 의 정보는 다음 페이지를 보시면 됩니다.

http://www.lindevdoc.org/wiki//proc/pid/stat