Elasticache for Redis 도입 후 메모리 사용률이 점점 오르는 상황에 대해

Elasticache for Redis 를 도입한 후 메모리 사용률이 점점 오르는 상황에 대해서 기재한 글입니다
2023.12.27

안녕하세요 클래스메소드의 수재입니다.
이번에 Elasticache Redis를 도입한 후 긴 기간동안 메모리가 점진적으로 상승하는 일이 있었습니다.
해당 오류를 수정하며 알게 된 점을 적어보겠습니다.

어떤 일이 있었는가?

이미지와 같이 처음 Elasticache for Redis(이하 AWS Redis)클러스터를 도입한 이후 메모리 사용률이 점점 상승하였습니다.

프라이머리 노드 1개와 리드 레플리카 노드 1개의 클러스터이며 클러스터의 메인터넌스 시간은 있었지만 재부팅은 발생하지 않았습니다.
결국 사용률이 70프로 가까이 올라서 원인 조사 및 해결이 필요한 상황이었습니다.

결론부터

AWS Redis를 도입할 때 각 키의 TTL을 설정하는 부분이 빠져 있었습니다. 그래서 클러스터 가동부터 지금까지 계속 키가 남아있는 상태가 지속되어 온 것이 원인이었습니다.

원인 조사

메모리 사용률이 오르는 상황에 대해서는 공식 블로그가 있었습니다.(해당 블로그를 참고하시면 이 글에 기재된 TTL 뿐만 아니라 다른 문제에 대해서도 조사하는데 도움이 될 것이라 생각됩니다.)

또한 비슷한 사례를 찾아보니 예전 글이지만 지금과 거의 똑같은 상황이 기재된 글이 있었습니다.

조사한 결과를 바탕으로 Redis의 info를 확인해보니 실제로 TTL이 설정되지 않은 키가 쌓여있었습니다.

info keyspace
# Keyspace
db0:keys=15390967,expires=0,avg_ttl=0

어플리케이션 코드에서 Redis를 이용할 때 TTL을 설정하지 않은 것도 문제지만 Redis의 Eviction policiesmax memory도 확인할 필요가 있었습니다.
AWS Redis에서는 파라미터 그룹에서 해당 파라미터가 설정되어 있습니다.

우선 AWS Redis에서 max memory는 파라미터 그룹이아닌 예약 메모리를 설정하여야 합니다.
파라미터 그룹의 max_memory 파라미터는 설정 불가이며 기본 값이 정해져있습니다.

Redis에 액세스하여 max memory 를 확인해보면 문서에 기재된 값보다 낮으며 이는 예약 메모리로 설정된 메모리를 제외한 메모리입니다. 이 값만큼 메모리가 도달하게 되면 정의된 정책대로 키가 설정됩니다.
공식 문서에 따르면 권장하는 예약 메모리는 전체 메모리의 1/4 정도입니다.

Redis 2.8.22 이전 버전을 실행하고 있는 경우 Redis 2.8.22 이후 버전을 실행하는 것보다 백업 및 장애 조치를 위해 더 많은 메모리를 예약해야 합니다. 이러한 요구 사항은 ElastiCache for Redis가 백업 프로세스를 구현하는 방법이 다르기 때문입니다. 경험상, 2.8.22 이전 버전의 Redis 오버헤드에 대해서는 노드 유형 maxmemory 값의 절반을 예약하고 Redis 버전 2.8.22 이후에 대해서는 1/4을 예약합니다. - 공식 문서

예약 메모리는 파라미터 그룹의 reserved-memoryreserved-memory-percent 파라미터에서 설정가능하며 2017년 3월 16일을 기준으로 사용되는 파라미터가 다릅니다.(참고)
이번 케이스에서는 reserved-memory-percent 파라미터가 기본 값인 25가 설정되어 있었습니다.

Eviction policiesmaxmemory-policy 에 해당합니다.
이 파라미터의 기본 값은 volatile-lru 으로 TTL expire set 이 설정된 값 중 가장 오래 참조되지 않은(Least Recently Used Algorithm) 키를 삭제하는 정책입니다.
이번 케이스에서 이 파라미터가 기본 값으로 설정되어 있었기 때문에 사용 메모리가 max memory에 도달하였더라도 TTL이 설정되어 있지 않아 그대로 키가 쌓였을 것으로 예상됩니다.

원인을 알았으니 이어서 해결 방법을 알아보도록 하겠습니다.

해결 방법

단기적인 해결 방법

키가 쌓여서 메모리가 해소되지 않기 때문에 단기적인 해결 방법으로 키를 삭제해야 합니다. 저장되어 있는 키를 삭제해도 되는지 사전에 검토가 필요합니다.
AWS Redis가 세션 용도로 사용되고 있다면 문제가 없겠지만 만약 설정 파일 등을 저장하는 용도로 사용한다면 삭제 후 영향이 있을 수도 있습니다.
키를 삭제해도 문제가 없다는 것이 검증되었다면 아래 방법 중 하나로 키를 삭제합니다.

  • maxmemory-policy 변경
  • 클러스터 재시작(플러시, flush)

maxmemory-policy 변경은 기본 값으로 설정되어 있는 정책을 모든 키를 대상으로 LRU 알고리즘을 적용하여 키를 삭제하는 allkeys-lru 로 변경하는 방법입니다.
이 방법은 maxmemory-policy가 기본 값으로 설정되어 있으며 키에 TTL이 설정되어 있지 않다면 유효한 방법입니다.
정책을 변경하면 max memory 만큼 메모리가 사용되었을 때 오래된 키부터 삭제됩니다.

정책을 변경하는 방법은 키를 점진적으로 삭제하는 방법이며 만약 한번에 키를 모두 비우고 싶다면 클러스터를 재부팅합니다.1
클러스터를 재부팅하면 모든 데이터를 플러시하기 때문에 빈 클러스터로 다시 시작됩니다.

혹시 재부팅으로 모든 키가 삭제되지 않았다면 플러시로 특정 DB 혹은 모든 DB의 키를 지우는 방법도 있습니다.

중장기적인(근본적인) 해결 방법

단기적인 방법으로는 지금 당장의 메모리 해소가 될 뿐 근본적인 방법은 되지 않습니다.
따라서 어플리케이션 코드에서 AWS Redis에 키를 만들 때 TTL을 설정하도록 수정해야합니다.
이후 maxmemory-policy 를 필요에 따라 다시 설정합니다.

마무리

캐시를 사용하면 더 쾌적한 경험을 제공할 수 있지만 단순히 도입하는게 끝이 아닌 최적화 등도 잊지 말아야 한다는 것을 다시 느낀 케이스였습니다.

긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 must01940 지메일로 연락주시면 감사합니다.


  1. 클러스터에 AOF가 설정되어 있다면 재부팅을 해도 데이터가 남아있습니다.