DB

[PostgreSQL] 서버 재시작하지 않고 무중단으로 SWAP 메모리 초기화 하는 방법 & 이슈 대처 방법 포함

swap 메모리가 올라가는 이유는?

Swap 메모리가 올라가는 근본적인 이유는 물리 메모리(RAM)가 일시적이든 지속적이든 부족했기 때문이며, 리눅스 커널이 시스템을 유지하기 위해 RAM의 데이터를 디스크(Swap)로 옮겼기 때문입니다.

조금 더 구체적으로 DB 서버에서 Swap이 차오르는 핵심 이유는 다음과 같습니다.

1. 순간적인 메모리 유입량 초과 (가장 흔함)

  • 평소에는 RAM 사용량(MEM Used)이 28% 수준으로 낮아 보이지만, 특정 시간대에 무거운 배치 작업(Batch), 대규모 조회(Select) 쿼리, 혹은 동시 접속자(Connection)가 급증했을 수 있습니다.
  • 이 순간 RAM이 일시적으로 100% 가까이 차오르면, 리눅스 커널은 당장 급한 작업에 RAM을 주려고 “지금 당장 일 안 하고 노는 프로세스의 데이터”를 Swap 공간으로 쫓아냅니다.
  • 이후 트래픽이 빠져나가서 RAM 사용량이 다시 28%로 내려가더라도, Swap으로 한 번 쫓겨난 데이터는 다시 누군가 강제로 요청하기 전까지는 RAM으로 자동 복귀하지 않고 Swap에 그대로 박혀있게 됩니다. 이 때문에 겉보기에는 RAM이 널널한데 Swap만 높게 유지되는 현상이 발생합니다.

2. 리눅스의 기본 메모리 관리 정책 (swappiness)

  • 리눅스는 RAM이 남아있더라도 “자주 안 쓰는 데이터는 차라리 Swap에 보관하고, 남는 RAM 공간을 디스크 캐시(buff/cache)로 활용하여 서버 전체 파일 읽기 속도를 높이는 게 이득이다”라고 판단하도록 기본 설정(기본값 60)되어 있습니다.
  • 이 설정 때문에 DB 서버처럼 파일 읽기/쓰기가 많은 환경에서는 시간이 지날수록 Swap이 야금야금 차오르게 됩니다.



무중단으로 SWAP 메모리 초기화 하는 방법

DB 서버를 재기동하지 않고 Swap 메모리를 정리하려면 물리 메모리(RAM)의 여유 공간을 확보한 후 Swap을 비활성화했다가 다시 활성화해야 합니다.

단, Swap 정리 작업 중에는 순간적으로 RAM 사용량이 급증하므로, 반드시 실제 여유 메모리(Free RAM)가 현재 사용 중인 Swap 용량보다 큰지 확인한 후 진행해야 합니다.


1단계: 메모리 상태 상세 확인 (반드시 선행)

터미널에서 아래 명령어를 입력하여 현재 실제 남은 RAM 용량과 Swap 사용 용량을 Byte 단위로 정확히 비교합니다.

free -h

주의 조건: free 또는 available 메모리가 현재 사용 중인 Swap 메모리 크기보다 더 커야 2단계 작업을 안전하게 진행할 수 있습니다.


2단계: 캐시 메모리 비우기 (선택 사항이지만 권장)

Swap에 있는 데이터를 RAM으로 가져오기 전에, RAM을 최대한 확보하기 위해 버퍼와 페이지 캐시를 정리합니다. (DB 서비스에 영향을 주지 않는 안전한 명령입니다.)

sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

하지만 대용량 DB 서버나 디스크 I/O가 빈번한 운영 환경에서는 순간적으로 서비스 성능이 크게 저하되는 부작용이 발생할 수 있습니다. 발생 가능한 구체적인 상황과 리스크는 다음과 같습니다.

1. 순간적인 CPU 및 디스크 I/O 부하 급증

  • echo 3 명령을 내리면 커널은 메모리에 있던 파일 캐시(Page Cache)를 비우기 전에 디스크와 동기화되지 않은 데이터를 먼저 디스크에 기록(sync)해야 합니다.
  • 이 과정에서 디스크 쓰기(Write) 작업이 순간적으로 몰리면서 디스크 I/O 수치가 100%까지 치솟을 수 있습니다. 이로 인해 서비스의 쿼리 응답 속도가 일시적으로 느려질 수 있습니다.

2. Read 쿼리 처리 속도 저하 (Cache Miss)

  • DB 서버는 자주 조회하는 데이터를 메모리(캐시)에 올려두고 빠르게 응답합니다. 하지만 캐시를 강제로 비워버리면, 이후 들어오는 조회 요청들은 메모리가 아닌 느린 물리 디스크에서 직접 데이터를 읽어와야 합니다(Cache Miss).
  • 캐시가 다시 채워질 때까지(Warm-up 기간) 쿼리 수행 시간이 평소보다 길어질 수 있으며, 이 동안 사용자가 서비스 지연을 느낄 수 있습니다.

3. 명령어 실행 지연 (수 초~수 분 대기)

  • 메모리에 쌓여있는 캐시 용량이 클수록(현재 서버는 5.4GiB로 다소 많은 편입니다) 이를 정리하고 디스크에 쓰는 데 시간이 걸립니다.
  • 명령어를 엔터 치고 나서 바로 프롬프트가 떨어지지 않고, 몇 초에서 길게는 1~2분간 멈춰있는 것처럼 보일 수 있습니다. 이는 락이 걸린 것이 아니라 커널이 내부적으로 메모리를 정리하는 중이므로 강제로 취소(Ctrl + C)하지 말고 기다리셔야 합니다.

리스크를 최소화하며 안전하게 수행하는 방법

현재 운영 중인 DB 서버의 트래픽이 몰리는 시간대라면 즉시 실행하는 것은 피하는 것이 좋습니다. 아래 가이드를 참고해 주세요.

  1. 동접자가 적은 시간대(새벽 또는 점검 시간)에 수행하는 것이 가장 안전합니다.
  2. echo 3 대신 echo 1을 먼저 시도해 볼 수 있습니다.
    • 1: 페이지 캐시(파일 읽기/쓰기 캐시)만 비우기 ➔ DB 서버에서 가장 효과적이며 리스크가 적음2: inode 및 dentry 캐시(디렉토리 구조 캐시)만 비우기3: 1번과 2번을 모두 비우기
sudo sync && echo 1 | sudo tee /proc/sys/vm/drop_caches

---------------------------------------------------------
명령어의 구성 요소를 뜯어보면 다음과 같습니다:

• sudo sync: 메모리에만 남아있던 변경된 파일 데이터를 물리 디스크에 즉시 안전하게 기록(동기화)합니다. 로키 리눅스의 필수 명령어입니다.
• &&: 앞의 sync 작업이 에러 없이 무사히 완료되면 뒤의 명령어를 실행하라는 뜻입니다.
• echo 1: 커널에 '페이지 캐시만 비워라'라는 신호(값 1)를 보냅니다.
• | sudo tee ...: 일반 관리자 권한 권한 분리 장치입니다. /proc/sys/ 경로는 보안상 sudo echo 1 > ... 방식으로 직접 쓰기가 안 되기 때문에, tee 명령어를 조합하여 안전하게 값을 입력하는 리눅스 표준 표준 표준 표준 기법입니다
  • echo 1만 실행해도 현재 부족한 free 메모리는 충분히 확보될 가능성이 높습니다.
  • 종료 후 free -h명령어로 확보된 가용 메모리를 확인합니다.


3단계: Swap 끄고 다시 켜기 (초기화 핵심)

Swap을 오프라인으로 전환하면 리눅스 커널이 Swap에 있던 데이터를 물리 메모리(RAM)로 모두 이동시킵니다. 이동이 완료되면 Swap이 0%로 초기화됩니다. 이후 다시 Swap을 켭니다.

# 1. Swap 비활성화 (데이터를 RAM으로 이동, 수 분 소요될 수 있음)
sudo swapoff -a
  • 절대 창을 닫거나 Ctrl + C를 누르지 말고 끝까지 기다려 주세요.
  • 참고: swapoff 명령을 내리면 데이터 이동을 위해 잠시 터미널이 대기 상태(블로킹)가 됩니다. 작업이 끝날 때까지 창을 닫지 마세요.
  • swapoff -a 명령어를 실행하는 동안, 다른 터미널 창을 하나 더 열어서 vmstat 1 또는 top 명령어로 메모리가 잘 이동하고 있는지 실시간으로 모니터링하는 것을 권장합니다.


# 2. Swap 다시 활성화
sudo swapon -a


sudo swapoff -a를 실행하면 Swap에 있던 데이터(약 1.6GiB)가 그대로 RAM으로 밀려 들어오기 때문에, RAM 사용량(Used)이 즉시 그만큼 껑충 올라가게 됩니다.

이 올라간 RAM 사용량이 언제, 어떻게 내려가는지에 대한 메커니즘은 다음과 같습니다.

1. 자동으로 바로 내려가지는 않습니다 (리눅스의 메모리 보존 정책)

리눅스 커널은 한 번 RAM에 로드된 데이터를 일부러 먼저 지우지 않습니다. “나중에 또 쓸 수도 있으니까 일단 RAM에 보관하자”라는 정책을 쓰기 때문입니다. 따라서 Swap을 비운 직후 올라간 RAM 사용량은 아무런 작업도 하지 않으면 그 상태 그대로 계속 유지됩니다.

2. RAM 사용량이 다시 내려가는 시점 (3가지 케이스)

올라간 RAM 사용량은 다음과 같은 상황이 발생할 때 자연스럽게 내려갑니다.

  • PostgreSQL 내부 세션/커넥션이 종료될 때 (가장 큼): Swap에 있던 데이터의 대부분은 과거에 무거운 쿼리를 날렸던 사용자의 연결 세션이거나 임시 작업 공간 데이터입니다. 웹 애플리케이션이나 개발자들이 DB 연결을 끊거나, 일정 시간 유휴 상태(Idle)가 되어 DB 세션이 종료되는 시점에 해당 메모리가 운영체제(OS)로 반환되면서 RAM 사용량이 뚝 떨어집니다.
  • 새로운 대용량 작업이 들어와 RAM이 진짜로 필요해질 때: 다른 프로세스가 대용량 RAM을 요구하면, 커널은 현재 RAM에 있는 데이터 중 “오랫동안 쓰지 않은 데이터”를 스스로 판단하여 메모리에서 해제(Free)해 버립니다.
  • DB 서비스를 재기동할 때 (인위적인 초기화): 정기 점검 등 추후에 PostgreSQL 서비스를 재기동(systemctl restart postgresql)하게 되면, DB가 붙잡고 있던 모든 메모리가 일시에 완전히 청소되면서 RAM 사용량이 초기 상태로 완전히 내려갑니다.


💡 향후 재발 방지를 위한 팁: vm.swappiness 조절

리눅스는 RAM이 남아있어도 특정 상황에서 Swap을 적극적으로 사용하려는 경향이 있습니다. 특히 DB 서버에서는 Swap을 최소화하는 것이 성능에 좋습니다.

Swap 초기화가 모두 끝난 후, 다음 트래픽 급증 시 또 Swap이 차오르는 것을 막으려면 RAM이 90% 이상 거의 꽉 찼을 때만 Swap을 쓰도록 정책을 바꿔야 합니다.

1.현재 설정 값 확인 (기본값은 대개 60)

cat /proc/sys/vm/swappiness

2.임시로 값을 10으로 변경 (RAM이 거의 가득 찼을 때만 Swap을 쓰도록 설정)

sudo sysctl vm.swappiness=10
  • 서버 재부팅시 원래 값으로 되돌아갑니다.

3.영구 반영 (/etc/sysctl.conf 파일 맨 아래에 추가)

vm.swappiness = 10

또는

# 파일 맨 아래에 설정값을 추가하는 명령어입니다.
echo "vm.swappiness = 10" | sudo tee -a /etc/sysctl.conf


만약 작업 중 PostgreSQL이 중단되었다면?

아래 명령어로 즉시 복구합니다. 로키 리눅스(Rocky Linux)에서 PostgreSQL 서비스를 즉각 제어하고 모니터링하는 명령어 세트입니다.

1. PostgreSQL 즉각 재기동 명령어

# 기본 서비스명으로 시작
sudo systemctl start postgresql

# 버전이 지정된 서비스명으로 시작 (버전에 맞게 숫자 변경)
sudo systemctl start postgresql-14

  • 만약 서비스명을 찾을 수 없다는 에러(Failed to start postgresql.service: Unit not found.)가 발생하면, 아래와 같이 버전 숫자가 포함된 서비스명을 사용해야 합니다.
    (예: PostgreSQL 14 버전인 경우)

2. 정상 작동 여부 확인 (필수)

서비스를 시작한 후, 실제로 잘 구동되어 연결을 받고 있는지 반드시 상태를 확인해야 합니다.

# 서비스 상태 확인
sudo systemctl status postgresql
# (또는 버전에 맞게)
sudo systemctl status postgresql-14
  • 화면에 초록색 글씨로 Active: active (running)이라고 표시되면 정상적으로 복구된 것입니다.


3. 죽은 원인 및 에러 로그 즉시 확인

만약 위의 start 명령어를 내렸는데도 에러가 나면서 켜지지 않는다면, 시스템 저널 로그를 통해 최근 50줄의 에러 기록을 바로 확인합니다.

sudo journalctl -u postgresql -n 50 --no-pager
# (또는 버전에 맞게)
sudo journalctl -u postgresql-15 -n 50 --no-pager

Hi, I’m 관리자