본문 바로가기

소프트웨어 이야기/데이터 저장소 + 시각화

[Redis]메모리 관리 방식

조사 배경

TTL이 만기된 캐시키들이 삭제(evicted)되지 않는 현상을 발견하면서, 레디스에서 메모리를 관리하는 방법이 궁금해졌다



알게된 것

* 레디스는 아래의 세가지 상황 때, 메모리를 정리한다.
   A. 만료된 키를 가져올 때
   B. 샘플링한 데이터 중에 만료된 키가 있는 경우
   C. 메모리 관리 정책을 설정했을 때,  논리적인 데이터 사용량이 maxmemory를 초과한 경우 
       => 실제 사용량으로 잡히는 rss를 기준으로 메모리를 정리하지 않는다.
* 레디스는 jemalloc을 쓴다.

* 용량이 큰 데이터를 자주 썼다가, 지우면 파편화가 발생하기 쉽다. 그리고 데이터의 크기 편차가 크면, 파편화가 생기기 쉽다. 실제 사용량보다 rss가 높게 나온다는 거다. 이 경우를 해결하려면, 장비를 이전하는게 낫다. 데뷰에서 카카오에서 레디스를 사용한 후기가 언급되었었는데, 좋은 방법은 없다고 한다. 주기적으로 데이터를 지워줬다고 한다. ( DEVIEW2014 -ARCUS차별기능,사용이슈,그리고카카오적용사례 )

* OOM 에러는 데이터를 저장할 수 없을 때 발생하는 에러다.


레디스 메모리 정리 방식별 고려사항 

B. 샘플링한 데이터 중에 만료된 키가 있는 경우 

* 레디스 서버는 디폴트로 1초에 10번(100ms마다) databasesCron()을 실행해서 만료된(expire) 키를 삭제한다. 참고

   redis나 sentinel이나 일정 주기로 처리되야 하는 로직을 정의 한 곳이 serverCron(..)이다. ( 참고 )

  * 그리고 이 안에서 databaseCron() 함수가 100 millisecond마다 수행된다. ( 참고 )

  * databaseCron(..)을 보면 active_expire_enabled 설정이 true이고 slave모드가 아니라면 activeExpireCycle(..)실행하게 되어 있다. activeExpireCycle(..)에서는 랜덤 샘플링을 이용하여 키들을 expire시킨다.  ( 참고 )

* 만료된 키를 삭제하는 주기를 짧거하거나, 메모리 사용량이 높은 객체는 나눠서 저장하는게 캐시를 빠르게 삭제하는 데에 도움이 된다. ( 참고 )

* 샘플링 수를 무조건 늘리는게, 좋은건 아니다. redis는 싱글 쓰레드 구조로 되어 있다. 때문에 샘플링 개수가 많아지면, 처리속도가 지연되게 된다. 그래서 다른 요청에 대한 응답 또한 지연된다. 


C. 메모리 관리 정책을 설정했을 때,  논리적인 데이터 사용량이 maxmemory를 초과한 경우  

 Redis의 LRU 알고리즘은 정확하지 않다. ( 참고 )



는 중인 것들

레디스 메모리 문제로 카오스를 겪는 사람을 전세계인이 도와주고 있는 이슈 해결 글 :  https://github.com/antirez/redis/issues/2136

Redis 메모리 삭제 코드 (freeMemoryIfNeeded) 분석 - server.c, evit.c

것들

레디스 Expire 처리방법 - http://pigbrain.github.io/opensource/2015/02/18/RedisMemoyPolicyAboutExpireData_on_Redis 

레디스 파편화 팁 - https://charsyam.wordpress.com/2017/05/27/혀로그래머-charsyam은-구라쟁이-2-캐시-멤캐시나-레디스-쓰/ 

유용한 사이트
redisgate - http://redisgate.jp/redis/configuration/redis_conf.php