Dukbong

[공식 문서 훑어보기] 1. Redis 기초 관리 - Linux, Memory 본문

Redis

[공식 문서 훑어보기] 1. Redis 기초 관리 - Linux, Memory

dukbong_dev 2025. 4. 27. 01:32
반응형

해당 내용은 Redis 공식문서를 기반으로 설정 관련 팁 중 Linux에 대해 작성하였습니다.

아래 예시는 모두 Docker를 통해 Redis를 실행하고 있습니다.


Linux

1. Redis는 Linux 환경에서 사용하세요.

Redis를 운영할때는 Linux 운영 환경에서 하는 것을 권장합니다.

물론 Mac OS, FreeBSD, OpenBSD에서도 테스트가 진행되었기 때문에 사용은 할 수 있지만 Linux 환경에서 가장 많은 테스트가 진행되었기 때문입니다.

2. vm.overcommit_memory 설정을 해주세요.

Linux 환경에는 vm.overcommit_memory라는 옵션이 존재합니다.

해당 옵션을 이해하기 위해서는 Memory Commit에 대해 먼저 알아보겠습니다.

2-1. Memory Commit 이란?

프로세스가 시스템 콜을 통해 메모리 할당을 요청하면 커널은 요청된 메모리 크기만큼의 주소 공간을 프로세스에게 반환하게 됩니다.

이 시점에서 커널은 해당 주소 공간을 실제 물리 메모리(RAM)에 바인딩하지 않습니다.

이는 "요청은 받았지만 아직 실제 메모리를 쓰고 있는 것은 아니다."라는 의미로 커널은 프로세스가 반드시 그 메모리를 실제로 사용할 것이라고 보장하지 않기 때문에 지연 바인딩 전략을 사용합니다.

 

이처럼 프로세스는 메모리를 "할당 받았다!"고 믿지만 실제로 물리 메모리가 할당된 것은 아닌 상태를 Memory Commit이라고 합니다.

실제 프로세스가 해당 메모리에 접근하면 그때는 물리 메모리(RAM)에 바인딩합니다.

2-2. 왜 vm.overcommit_memory를 설정할까?

시스템에 3GB의 물리 메모리(RAM)가 있고 A 프로세스가 2GB를 사용 중이라고 가정해봅시다.
이 상태에서 A 프로세스가 fork()를 호출하면 B 프로세스가 생성되며 A와 동일한 2GB의 메모리 공간을 복사하게 됩니다.  
이는 잠재적으로 총 4GB의 메모리 공간이 필요하다는 의미이며 이 중 2GB는 커밋된 상태가 됩니다.
이처럼 실제 물리 메모리보다 더 많은 메모리가 커밋되면 시스템은 overcommit 상태가 됩니다.
이러한 상황에서 Redis는 fork() 중 Out Of Memory 오류가 발생하는 것을 방지하기 위해 vm.overcommit_memory= 1로 설정하는 것을 권장합니다.

2-3. vm.overcommit_memory 확인 및 설정 방법

기본적으로 vm.overcommit_memory는 0(disable) 입니다.

// 확인 방법
sysctl vm.overcommit_memory

// 설정 방법
sudo sysctl vm.overcommit_memory = 1, 0

3. Redis는 작은 데이터 블록을 좋아해요.

기본적으로 컴퓨터는 4KB 단위로 메모리 할당을 처리합니다.

하지만 Linux 운영 환경은 성능 향상을 위해 2MB 단위로 메모리를 묶어서 CPU 작업량을 줄여 성능을 개선하고 있지만 Redis와 같은 in memory DB에서는 큰 묶음 단위가 성능에 악영향을 줄 수 있습니다.

Redis는 작은 데이터를 빠르게 처리하는 것이 핵심이므로 2MB 크기의 메모리 할당을 처리하면 할당과 해제 과정에서 지연이 발생할 수 있습니다.

이는 실시간 반응을 요구하는 서비스에서 응답 시간을 증가시키고 결국 Redis 성능에 부정적인 영향을 미칠 수 있습니다. 따라서 transparent_hugepage를 비활성화하면 4KB 단위로 메모리가 할당되어 성능이 개선될 수 있습니다.

3-1. transparent_hugepage 확인 및 설정 해제 방법

아래 명령어를 통해 현재 설정 상태를 확인 할 수 있으며 현재 상태는 []로 표시됩니다.

cat /sys/kernel/mm/transparent_hugepage/enabled

아래 명령어를 통해 설정을 해제 할 수 있습니다.

// 권한 문제가 있을 수 있습니다.
echo never > /sys/kernel/mm/transparent_hugepage/enabled
// 권한 문제가 일어나지 않습니다.
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

아래 명령어를 통해 설정을 기본값으로 되돌릴 수 있습니다.

// 권한 문제가 있을 수 있습니다.
echo always > /sys/kernel/mm/transparent_hugepage/enabled
// 권한 문제가 일어나지 않습니다.
echo always | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

주의 해야할 점은 위 명령어는 휘발성 설정이기 때문에 서버를 재부팅하면 설정이 초기화됩니다.

 

재부팅 후에도 적용하려면 GRUB 설정을 변경해야 합니다.

sudo vi /etc/default/grub

아래 옵션 중 하나를 선택하여 설정합니다.

// 1. 기본적인 부팅 옵션을 설정
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash transparent_hugepage=never"

// 2. 커널 파라미터를 설정
GRUB_CMDLINE_LINUX="crashkernel=auto rhgb quiet transparent_hugepage=never"

설정 파일을 저장 후 GRUB을 업데이트한 후 재부팅합니다.

sudo update-grub
sudo reboot

Memory

1. Swap은 싫지만 설정은 해줘야해요.

우선 Swap이란 시스템 메모리(RAM)가 부족할 때 디스크의 일부를 마치 메모리처럼 사용하는 영역을 말합니다.

RAM에 비해 디스크는 수백~수천 배 느리기 때문에 성능 저하가 심각할 수 있습니다.

 

Redis의 데이터가 많아져서 메모리 용량을 초과하게 되면 메모리 부족이 발생할 수 있습니다.

이때 Redis는 두 가지 방식으로 대응할 수 있습니다.

  1. Out of Memory (OOM) 오류 발생 : 비정상 종료
    • 단, maxmemory 설정에 따라 데이터 삭제가 진행 될 수 있습니다.
  2. Swap 사용 : 계속 운영 가능

Swap을 사용하는 것은 RAM에 비해 수백~수천 배 느린 디스크에서 I/O 작업을 통해 읽고 쓰는 것이기 때문에 응답 시간이 급격히 증가할 수 있기 때문에 Redis의 메모리 사용량을 주의 깊게 모니터링하고 적절한 Swap 공간을 설정하는 것이 중요합니다.

잊지 말아야 할 중요한 점은 Swap을 설정하되 실제로 Swap이 발생하지 않게 하는 것입니다.

 

1. Docker로 memory와 swap 크기를 지정할 수 있습니다.

docker run -d --name redis-test \
  # 메모리 제한 : 1GB
  --memory="1g" \      
  # 메모리 + 스왑 합산 : 2GB
  --memory-swap="2g" \ 
  redis
  
  # --memory-swap 값을 --memory와 동일하게 설정하면 스왑을 사용할 수 없습니다.
  # --memory-swap 값을 -1로 설정하면 명시적 제한 X 최대한 사용할 수 있습니다.

2. Docker를 통해 Swap 사용을 모니터링할 수 있습니다.

 

컨테이너의 메모리 사용량, Swap 사용량, Block I/O(디스크 읽기/쓰기) 등을 실시간으로 확인할 수 있습니다.

특히 Block I/O 수치가 비정상적으로 높다면, 디스크를 통한 Swap이 발생하고 있을 가능성이 있습니다.

docker stats redis-test

3. Redis-cli를 통해 Swap 사용 의심을 모니터링할 수 있습니다.

mem_fragmentation_ratio 지표를 확인하면 Redis의 메모리 조각화 및 Swap 사용 여부를 간접적으로 판단할 수 있습니다.

  • used_memory_rss / used_memory = mem_fragmentation_ratio

이 비율이 1.5를 초과하게 되면 실제 필요한 메모리보다 훨씬 많은 물리적 메모리가 사용되고 있음을 의미하며 Swap 발생 가능성을 의심해볼 수 있습니다.

> INFO memory

used_memory:2345678          // Redis가 실제로 사용한 메모리 - 논리적
used_memory_human:2.24M      // used_memory 보기 좋은 버전
used_memory_rss:3456789      // OS에서 Redis가 차지하는 메모리 - 물리적
used_memory_rss_human:3.29M  // used_memory_rss 보기 좋은 버전
mem_fragmentation_ratio:1.47 // 메모리 조각화 비율
...

2. MaxMemory를 설정해주세요.

Redis에 maxmemory를 설정하면 Redis가 최대 얼마나 메모리를 사용할 것인지 명시적으로 지정할 수 있습니다.

이 설정을 통해 Redis는 설정된 메모리 한도에 도달했을 때 오류를 발생시키거나 데이터를 삭제하여 메모리 사용량을 조정하는 등의 정책을 적용하게 됩니다.

 

maxmemory 설정이 없다면 Redis는 시스템의 메모리가 소진될 때까지 데이터를 계속해서 저장합니다.

이로 인해 시스템 전체에 심각한 성능 저하나 비정상 종료(Out of Memory) 문제가 발생할 수 있기 때문에 이를 방지하려면 Redis가 사용할 메모리의 최대 한도를 명시적으로 설정하는 것이 중요합니다.

 

서버에 여유 메모리가 있다고 해도 Redis에 메모리를 100% 할당하는 것은 추천되지 않습니다.

Redis는 내부적으로 메모리를 사용하며 메모리 조각화로 인한 손실이 발생할 수 있기 때문에 여유 공간을 고려해 메모리를 설정하는 것이 중요합니다.

 

공식 문서에서는 "10GB의 여유 메모리가 있을 경우, 8GB 또는 9GB 정도로 설정하는 것이 안전하다” 라고 되어 있지만 maxmemory는 Redis가 사용하려는 최대 메모리 양을 설정하는 것이므로 실제로 Redis가 사용하는 메모리는 이보다 클 수 있다는 점을 염두에 두어야 합니다.

 

1. maxmemory 설정 및 정책 설정

docker run -d --name redis-test \
  # 시스템 메모리 3G
  --memory="3g" \
  # 시스템 메모리 + 디스크 4G
  --memory-swap="4g" \
  redis \
  # Redis 최대 사용 메모리 2G
  # 2G 넘어서면 가장 오래 사용되지 않은 키(LRU) 를 삭제
  redis-server --maxmemory 2gb --maxmemory-policy allkeys-lru

2. Redis-cli에서 설정하는 방법

CONFIG SET maxmemory 2gb

3. redis.conf 파일을 통해 설정 값 저장

# 메모리 사용량 제한
maxmemory 2gb

# 메모리 초과 시 정책
maxmemory-policy allkeys-lru

4. Redis에서 사용할 수 있는 기본적인 메모리 정책

  • allkeys-lru : 모든 키에 대해 가장 덜 사용된(LRU 알고리즘) 키를 삭제
  • allkeys-random : 모든 키 중 무작위 선택 삭제
  • volatile-lru : expire 시간이 설정된 키  가장 덜 사용된(LRU 알고리즘) 키를 삭제
  • volatile-random : expire 시간이 설정된 키들 중에서 무작위로 삭제
  • noeviction : 데이터를 삭제하지 않고 새로운 데이터를 삽입할 수 없으며 클라이언트에게 오류 발생

5. redis.conf를 사용한 설정

docker run -d --name redis-test \
  # 시스템 메모리 3G
  --memory="3g" \
  # 시스템 메모리 + 디스크 4G
  --memory-swap="4g" \
  # redis.conf 경로
  -v ~/redis.conf:/usr/local/etc/redis/redis.conf \
  redis \
  # redis.conf 경로
  redis-server /usr/local/etc/redis/redis.conf

3. Redis의 Memory는 뻥튀기 됩니다.

Redis는 휘발성이 강한 인메모리 데이터베이스이기 때문에 메모리 내에서 데이터를 처리합니다.

하지만 데이터를 영속적으로 저장하기 위해 RDB 파일을 디스크에 저장하거나 AOF 로그를 작성할 필요가 있습니다.

이때 Redis는 일시적으로 2배의 메모리를 사용할 수 있으며 이 현상은 쓰기 작업이 활발한 환경에서 자주 발생할 수 있기 때문에 메모리 사용량을 예측하고 서버를 적절히 설정하는 데 도움이 됩니다.

3-1. RDB? AOF?

※ RDB (Redis Database) 스냅샷

일정한 시간 간격으로 Redis의 모든 데이터를 디스크에 저장하는 방식입니다.

Redis는 메모리에서 데이터를 디스크로 덤프하여 저장하며 이 과정에서 디스크 I/O가 발생합니다.

 

  AOF (Append-Only File)

모든 쓰기 작업을 로그 파일에 추가하는 방식입니다.

AOF 파일이 커지면 Redis는 주기적으로 기존 파일을 새로 작성하여 불필요한 명령을 제거하고 파일 크기를 줄입니다.

3-2. 왜 뻥튀기 될까?

Redis는 데이터를 디스크에 저장하거나 AOF 파일을 재작성할 때 메모리 사용량이 최대 두 배로 증가하는데 주로 디스크에 반영되는 과정에서 발생하는 현상입니다.

이때 메모리 페이지(메모리 상의 데이터 블록)가 수정되면서 추가적인 메모리 공간이 필요하게 되는데 이 추가 메모리는 디스크 저장이 완료될 때까지 Redis에서 임시로 사용됩니다.

 

예시를 들어 Redis에 수천 개의 키가 있고 이들 중 일부가 수정된다면 Redis는 이 수정된 키들에 대한 복사본을 메모리 내에서 생성 하게 되는데 이러한 복사본은 디스크에 저장되는 RDB 스냅샷이나 AOF 파일을 작성하는 동안 필요한 데이터를 임시로 저장합니다.

이 과정에서 메모리 사용량이 최대 두 배로 증가할 수 있습니다.

▶▶ 하지만 실제로 2배가 일어나려면 모든 키에 대해 수정이 일어나야 합니다.

3-3. 메모리 크기는 어느정도가 적절할까?

Redis의 메모리 설정을 적절히 조정하는 것이 중요한데 이유는 쓰기 작업이 많은 시스템에서 메모리가 최대 두 배로 증가할 수 있음을 염두에 두고 서버의 메모리 용량을 설정해야 합니다.

  • 쓰기 작업은 키 생성, 수정, 삭제가 있습니다.

예를 들어 시스템에 여유 메모리가 8GB가 있다면 최대 메모리는 8G보다 낮으며 Swap 공간도 적절히 설정하고 메모리가 뻥튀기 되는 정도를 생각하고 설정하면 RDB 스냅샷 작성이나 AOF 로그 재작성 과정 중에도 시스템이 안정적으로 동작할 수 있습니다.

 

극단적인 예시로 최대 메모리 3GB, Swap 1GB, maxmemory 2GB로 설정된 상태에서 모든 키를 수정하게 되면 RDB 스냅샷 생성 및 AOF 로그 재작성 과정에서 Redis가 기존 데이터와 수정된 데이터를 메모리에 동시에 유지하게 되어 총 4GB의 메모리가 사용될 수 있습니다.

이러한 상황에서는 Redis가 Swap을 사용하게 되면 성능 저하가 발생할 수 있고 이로 인해 서비스가 불안정해질 수 있으며 서비스의 비정상 종료까지 발생할 수 있습니다.

3-4. 메모리 모니터링은 Redis에서 할 수 있습니다.

Redis에서는 성능 문제를 진단하고 해결하는 데 유용한 도구들을 제공합니다.

두 가지 주요 도구는 LATENCY DOCTOR와 MEMORY DOCTOR입니다.

  • LATENCY DOCTOR
    • Redis의 지연 문제를 분석하고 지연을 일으키는 원인과 그 해결 방법을 제시하는데 주로 지연 패턴을 파악하여 성능 최적화에 도움을 줍니다.
  • MEMORY DOCTOR
    • Redis의 메모리 사용량을 분석하고 메모리 부족 문제나 비효율적인 메모리 사용에 대한 해결책을 제공합니다.
    • 메모리 누수나 불필요한 메모리 소비를 찾아내고 최적화하는 데 도움을 줍니다.
반응형
Comments