Redis는 인메모리 데이터베이스로, 데이터를 메모리에 저장하고 처리하기 때문에 메모리의 효율적인 사용이 서버의 성능과 안정성에 직접적인 영향을 미칩니다. 서버의 메모리 용량을 초과하거나 메모리 부족 상태가 발생하면 성능 저하나 심지어 시스템 장애가 발생할 수 있습니다.
Redis의 주요 장점은 인메모리를 통한 고속 처리입니다. 하지만 메모리 관리가 잘못되면 성능이 급격히 떨어질 수 있습니다. 메모리 단편화가 심해지면 새로운 데이터를 위한 연속된 메모리 블록 할당이 어려워져 성능 저하가 일어날 수 있습니다. 그리고 Redis의 데이터 구조나 데이터 크기 설정이 잘못되면 불필요하게 메모리를 많이 차지할 수 있습니다.
Redis를 클러스터나 복제 환경에서 운영하는 경우, 여러 노드 간 데이터 분배와 메모리 관리가 더욱 중요합니다. 각 노드가 적절히 메모리를 관리하지 않으면 일부 노드에 메모리가 과도하게 집중될 수 있고, 이는 결국 서버 장애나 클러스터 불균형을 초래할 수 있습니다.
위에서 살펴본 바와 같이 Redis에서 메모리 관리와 설정은 성능, 안정성, 비용 절감에 중요한 영향을 주기 때문에 적절한 메모리 설정을 통해 서버 과부하를 방지하고 문제를 조기에 발견하기 위해서는 메모리 사용 현황을 모니터링하여 최적화하는 것이 필요합니다.
1. used_memory
메모리 사용량은 cli 화면에서 “info memory”<그림 1> 명령을 통해 확인할 수 있습니다. 지표 중 used_memory는 Redis가 현재 사용하고 있는 전체 메모리 양을 바이트 단위로 표시합니다. used_memory_human은 사람이 읽기 쉬운 형식으로 수치를 제공합니다. “info memory”를 통해 제공된 메모리 사용량은 데이터를 저장하고 실행 지원을 위한 메타 데이터를 저장하기 위해 요청한 메모리 양을 반영합니다.
메모리 사용량은 Redis 성능에 중요한 요소로, used_memory가 가용 메모리를 초과하면 운영 체제가 swapping을 시작하여 성능이 크게 저하됩니다. swapping이란 오래되거나 사용하지 않는 메모리 영역을 디스크에 기록하여 새롭고 활성화된 공간을 생성하는 것을 말합니다.
<그림 1 info memory>
Redis는 데이터를 디스크에 주기적으로 저장하는 snapshot 기능을 제공하고 있으며, snapshot은 Redis의 영속성 메커니즘의 하나로 Redis RDB 파일에 데이터를 저장하여 서버가 재시작 되거나 장애가 발생했을 때 데이터 복구를 가능하게 해 줍니다. 이런 snapshot 기능의 활성화 및 비활성화는 다음 <그림 2>와 같이 설정으로 가능합니다.
<그림 2. redis.conf 에서 snapshot 설정>
Snapshot을 활성화하지 않을 경우에는 데이터가 손실되거나 가용 메모리의 95%를 초과하여 사용할 경우 swapping이 발생하고 Snapshot을 활성화할 경우에는 데이터를 디스크에 쓰기 전에 메모리에 복사본을 생성하는 작업이 수행되며 이 경우에는 가용 메모리의 45% 이상 사용 시 swapping이 발생할 수 있습니다.
메모리 사용량 관리를 하는 방법으로 다음과 같이 4가지 방법을 제시하고 있습니다.
알아두면 좋은!
레디스 메모리 사용량 관리법
1) 적절한 데이터 구조 사용
Redis는 다양한 데이터 구조(String, list, set, hash, sorted set 등)를 제공합니다. 따라서 데이터에 맞는 데이터 구조를 적절하게 선택하면 메모리 사용을 크게 줄일 수 있습니다. 또한 작은 크기의 key-value 쌍을 많이 저장할 때 hash를 사용하면 메모리 사용을 최적화할 수 있습니다. 다음 <그림 3>은 hash 사용의 예를 보이고 있습니다.
<그림 3. hash 사용 예>
2) Key의 TTL(Time to Live) 설정
Redis는 기본적으로 만료된 key를 자동으로 삭제하지 않기 때문에 메모리가 늘어나지 않도록 key를 제거하거나 key 만료 시간을 설정하여 사용하지 않는 key를 메모리에서 삭제시켜 메모리 사용량을 늘릴 수 있습니다. Key 만료 시간 설정은 다음 <그림 4>와 같이 할 수 있습니다.
3) maxmemory-policy 설정
maxmemory-policy에서 Redis 메모리가 제한을 초과했을 때 수행할 action을 설정할 수 있는데, 메모리 제한 초과 시 데이터를 삭제할 지 아니면, 추가적인 요청을 거부할지를 결정할 수 있습니다. maxmemory-policy 설정은 다음 <그림 5>와 같이 합니다.
<그림 5. maxmemory-policy 확인 명령어 및 redis.conf에서 설정 예>
4) mem_fragment_ratio 모니터링
mem_fragment_ratio를 모니터링하여 메모리 단편화가 심할 경우 Redis를 재시작하여 단편화를 제거할 수 있습니다. mem_fragment_ratio는 “info memory” 명령을 통해 확인이 가능하며 그 값이 1을 초과하면 단편화가 생긴 것으로 간주합니다.
2. Fragment Ratio
메모리 단편화란 OS나 프로그램이 memory를 효율적으로 사용하지 못하고, 사용 가능한 메모리가 여러 작은 조각으로 단편화가 되어 낭비되는 현상입니다. 메모리 기반 데이터베이스에서는 중요한 문제로 간주합니다. 이러한 단편화가 발생하는 원인의 첫 번째는, 물리 메모리를 비효율적으로 할당하는 것입니다. 운영체제가 Redis에 필요한 큰 메모리 블록을 제공할 때 연속된 페이지를 확보하지 못해 작은 조각으로 나뉜 segment 메모리 블록만 제공하게 되어 메모리 할당의 비효율성이 발생하고 결과적으로 단편화가 일어납니다.
두 번째 원인으로는 어플리케이션에서 빠른 서비스를 제공하기 위해 다양한 크기의 메모리 블록을 미리 예약하거나 할당하는 경우가 있는데 이 경우에는 실제 사용하지 않는 메모리 블록이 단편화를 발생시키게 됩니다.
메모리 fragment ratio 계산 식은 다음과 같습니다.
Used memory RSS는 OS가 Redis에 실제로 할당한 물리적 메모리 크기로 단편화로 인해 낭비되는 메모리도 포함된 수치입니다. Used Memory는 Redis가 실제로 사용한 메모리 수치입니다. 이렇게 계산된 fragment ratio는 인스턴스의 리소스 성능 이해 시 중요한 지표가 됩니다.
이렇게 계산된 fragment ratio 수치를 보고 성능 개선을 위해 다음과 같이 수행할 수 있습니다.
알아두면 좋은!
단편화 대비 레디스 성능개선
3. Latency Time
Latency time은 Redis server가 응답하는데 걸리는 평균 시간을 밀리 초 단위로 측정한 것으로 Redis의 성능 변화를 확인하는 직접적인 방법 중 하나입니다. latency time을 확인하는 방법은 cli에서 “redis-cli ?latency -h {host} -p {port}” <그림 6> 명령을 입력하면 확인할 수 있습니다. 일반적인 latency time은 1Gbps Network의 경우 약 200μs이고 이 시간 보다 latency time이 클 경우 성능 저하를 의심해 봐야 합니다.
<그림 6. latency time 확인하는 방법>
Latency time이 증가하는 주요 원인은 client가 요청한 명령이 오래 걸리거나 큰 결과를 요구할 때 다른 모든 요청들이 대기하는 현상이 발생하는 것입니다. Redis는 single process 처리를 기본으로 모든 client 요청을 처리하기 때문에 한 client 요청이 느리면 다른 요청이 대기할 수밖에 없는 구조입니다.
Latency time이 증가하면 commands 처리량과 latency time을 추적하여 문제 발생 시점을 파악하는 것을 선행하여 slow command가 있는지 또는 command queue에 명령어가 과도하게 쌓였는지 확인합니다. latency_time과 instantaneous_ops_per_sec지표를 확인하여 성능 저하가 의심될 경우 다음과 같이 2가지 방식으로 관리할 수 있습니다.
알아두면 좋은!
레디스 성능 저하 관리법
1) Slow command 식별
Redis slow log를 이용하여 사용자 지정 실행 시간을 초과하는 명령어를 식별합니다. Redis slow log에서 확인하는 방법은 cli에서 “slowlog get”<그림 7> 명령을 입력하면 됩니다. Redis slow log에서는 디폴트 기준값인 10ms를 초과하는 명령어를 기록하고 있으며 이 기준값을 변경하려면 “confit set slowlog-log-slower-than {value}” 명령어를 사용하면 됩니다.
<그림 7. slowlog get>
2) Client connection 제한
현재 연결되어 있는 클라이언트 수가 많으면 각 client에게 할당되는 지원 시간이 감소하여 결국에는 성능 저하의 요인이 됩니다. 현재 접속되어 있는 client 수를 확인하는 방법은 “info clients”<그림 8> 명령을 이용하여 확인할 수 있고 해당 명령어로 client 수를 확인한 후 최대 client 수를 제한하려면 “config set maxclients {value}” 명령어를 사용하여 maxclients limit를 설정하면 됩니다. 일반적인 설정 권장 범위는 최대 예상 connection 수의 110~150% 정도로 설정합니다.
<그림 8. info clients 에서 maxclients>
total_commands_processed 지표가 감소하는데도 latency time이 증가하면 slow command가 존재할 확률이 높으며, 메모리 사용량이 증가하면서 latency_time이 증가하면 swapping이 진행 중일 가능성이 높다는 것을 말합니다. 각 상황에 맞춰 관리하는 것이 중요합니다.
4. instantaneous_ops_per_sec
Redis에서 명령어를 처리한 수는 “info stats” <그림 9> 명령을 통해 확인이 가능합니다. total_commands_processed 지표는 누적값으로 Redis 서버가 시작된 이후 처리된 모든 명령의 총 개수를 말합니다.
total_commands_processed 값이 지속적으로 높은 값이 기록될 경우 서버의 부하 상태를 점검하거나 캐시 사용량의 최적화가 필요합니다. 일반적으로 total_commands_processed 값은 누적값으로 초당 변화량으로 부하 여부를 판단해야 하며 초당 변화량을 보여주는 지표는 “instantaneous_ops_per_sec” (초당 command 처리량) 입니다. 그리고 “instantaneous_ops_per_sec” 값이 높다고 반드시 Redis 서버에 부하가 있는 것은 아니며, 부하 여부는 리소스(CPU, Memory, Network 등) 사용량에 따라 판단해야 합니다.
또한 GET, SET과 같은 간단한 명령어의 경우에는 “instantaneous_ops_per_sec”가 높아도 부하가 적은 반면, SORT, ZRANGET, SCAN 등 복잡도가 높은 명령어의 경우 데이터 크기에 따라 부하가 커질 수 있습니다.
일반적인 부하 기준
Low Load: 0 ~ 10,000 ops/sec (Redis 서버 기본 처리 범위)
Moderate Load: 10,000 ~ 50,000 ops/sec (노드 크기와 작업 유형에 따라 다름)
High Load: 50,000+ ~ ops/sec (CPU, Memory, Network 대역폭을 면밀히 확인 필요)
instantaneous_ops_per_sec로 인해 성능 저하가 된다면 latency_time(지연 시간) 진단을 통해 확인할 수 있습니다. 일반적인 latency_time은 1Gbps Network을 기준으로 약 200μs 정도입니다. 처리할 명령어가 많아지면 명령어 queue에 명령어가 쌓이게 되고 응답 시간이 느려져 latency_time이 증가하게 됩니다. 또는 하나 이상의 slow command로 인해 latency_time이 증가할 수 있습니다. 명령어에 의한 성능 지표를 분석하려면 instantaneous_ops_per_sec값과 latency_time을 기록하는 스크립트를 설정하여 명령어 처리 수 변화와 응답 시간을 분석하면 됩니다.
latency_time에 따른 문제를 해결하는 방법은 다음과 같이 3가지를 제안하고 있습니다.
알아두면 좋은!
Latency Time 문제해결
1) 다중 인수 명령어 사용
많은 명령어들이 짧은 시간 내에 전송될 때 응답 시간이 느려질 수 있으므로 응답 시간이 느려 지는 것을 방지하기 위해 다중 인수를 허용하는 명령어를 사용하여 전체 명령어 처리량을 감소시키도록 합니다. 예를 들어 루프 구문을 사용하여 LSET을 1,000번 반복하는 대신 LPUSH나 RPUSH를 사용해 1,000개의 요소를 한 번에 추가하면 명령어 개수가 줄어들게 됩니다.
2) Pipeline command 사용
여러 개의 명령어들을 함께 파이프라인으로 수행하여 network latency time을 줄일 수 있습니다. 또는 모든 명령어들을 한 번에 전송해 network latency cost를 최소화하도록 하여 관리할 수 있습니다.
3) 큰 집합에 대해 slow command 회피
복잡도가 높은 오래 걸리는 명령어 사용 시 latency time이 증가하므로 큰 집합에서 이러한 명령어 사용을 최소화하여 성능을 개선할 수 있습니다. 다음은 장시간 수행될 수 있는 명령어와 보완 방법의 일부 예 입니다.
5. Evictions
Eviction이란 메모리 부족 상황에서 어떤 데이터를 삭제할 지 결정하는 정책 설정 기능입니다. 적절한 eviction 정책을 선택하여 데이터 삭제 전략을 관리하면 성능 최적화와 효율적인 메모리 관리가 가능합니다. “info stats”<그림 10> 명령을 이용하여 나오는 수치를 통해 evicted_keys 라는 항목으로 확인이 가능하며 evicted_keys는 maxmemory limit에 도달하여 삭제된 key 수를 말합니다. maxmemory limit이 설정되는 경우만 key 삭제가 가능하며 maxmemory limt을 설정하는 방법은 다음 <그림 11>과 같습니다.
<그림 10. info stats 에서 evicted_keys>
<그림 11. redis.conf에서 maxmemory limit 설정>
Maxmemory-policy의 설정에 어떤 방식으로 key를 삭제할 것인지 알고리즘을 설정할 수 있으며 다음 2가지 방식 중 하나로 설정할 수 있습니다.
1) volatile-lru: 가장 최근에 사용되지 않은 key 부터 삭제
2) volatile-ttl: 가장 만료 시간이 가까운 key 부터 삭제
evicted_keys는 Redis의 메모리 관리 상태를 확인하고 메모리 부족 문제를 추적하는데 유용한 지표이며 evicted_keys 값이 지속적으로 증가할 경우 Redis 메모리 한도가 자주 초과되고 있다는 것을 의미합니다. 즉, 메모리가 부족하기 때문에 eviction이 자주 발생하고 있다는 신호입니다. evicted_keys가 많이 증가하는 경우에는 다음과 같은 방법으로 관리할 수 있습니다.
알아두면 좋은!
Evicted keys 증가 대비 레디스 성능개선
1) maxmemory limit 증가
snapshot을 사용할 경우에는 maxmemory 값을 물리 메모리의 45%까지, snapshot을 사용하지 않을 경우에는 95%로 설정하는 것이 일반적입니다. maxmemory를 설정하려면 “config set maxmemory {value}” 명령을 통해 설정이 가능합니다.
2) Eviction 정책 조정
key 삭제에 더 적합한 알고리즘을 통한 메모리 관리를 수행하는 것입니다. 예를 들어 allkeys-lru 대신 volatile-lru 로 변경하면 만료된 key를 우선적으로 삭제하도록 설정할 수 있습니다.
3) 인스턴스 분할
데이터를 여러 인스턴스에 걸쳐 나누어 분할 저장하도록 합니다. 여러 컴퓨터의 resource를 결합하여 사용할 경우 가용 메모리가 증가할 수 있어 key 삭제나 메모리 swapping 없이 더 많은 key를 저장할 수 있습니다.
인스턴스를 분할하는 방법은 아래와 같이 3가지 방법을 제안하고 있습니다.
1) Hash partitioning: hash function을 사용하여 key이름을 특정 instance에 해당하는 숫자 범위로 매핑
2) Client-side partitioning: Redis client가 주어진 key에 대해 어느 instance에서 읽고 쓸지를 선택
3) Proxy partitioning: Redis client 요청이 proxy로 전송되며 proxy는 구성된 분할 schema에 따라 사용할 instance를 결정
Redis 성능 관리는 maxmemory와 eviction 정책을 사용하여 메모리 부족 상황에서 데이터를 삭제하는 방식으로 메모리를 관리하는 것이 더 적합합니다.
이상으로 Redis 5가지 성능 지표의 내용과 관리 방법에 대해 알아봤습니다.
작성: 기술연구소 김인태 이사
편집: 기술연구소 강민주 선임