AWS Lightsail 서버가 갑자기 멈춰서 원인 찾아본 기록 — Swap 확장으로 해결

어느 날 갑자기 서버가 먹통

Lightsail 2GB 인스턴스에서 WordPress + Next.js 앱 + Claude Code를 돌리고 있었는데, 어느 날 SSH 접속이 안 됐다. Lightsail 콘솔에서 재부팅하고 다시 들어가서 로그를 뒤져보니 OOM Killer가 프로세스를 죽인 흔적이 있었다.

“어제까지 잘 돌아갔는데?” 싶었지만, 생각해보면 빌드 한 번 돌리면 메모리가 순간적으로 치솟는 구조였다. 원인을 제대로 짚어보기로 했다.

서버가 멈추는 4가지 원인

원인 1 — 메모리(RAM) 부족 (제일 흔함)

리눅스는 메모리가 바닥나면 OOM Killer가 작동한다. “메모리가 없으니 제일 많이 쓰는 프로세스를 죽여서 살아남자”는 커널의 자동 방어 장치다.

내 상황: Apache + MariaDB + Node.js 앱 + Claude Code가 동시에 돌아가면 메모리 사용량이 1.8GB를 넘겼다. 여기서 빌드나 API 호출이 들어오면 2GB를 초과하면서 OOM Killer가 작동했다.

프로세스가 갑자기 죽거나 웹 서비스가 응답 안 하는 현상이 반복되면 메모리부터 의심하자.

원인 2 — CPU 버스트 크레딧 소진

Lightsail은 EC2 T 시리즈와 같은 버스트 가능(Burstable) CPU를 쓴다. 평소에 조금 쓰면서 크레딧을 모으고, 필요할 때 풀 파워를 내는 방식이다.

상태 CPU 사용 크레딧
평상시 기준치 이하 (5~10%) 축적
빌드/트래픽 급증 100% 소모
크레딧 소진 후 5~10%로 제한 회복 대기

크레딧이 다 떨어지면 CPU가 5~10%로 제한되어서 모든 게 극도로 느려진다. 프로세스가 죽지는 않고 살아있는데 응답이 안 오면 이 경우일 가능성이 높다.

메모리 부족과의 차이: 메모리 부족은 프로세스가 갑자기 죽고, 크레딧 소진은 프로세스는 살아있지만 전부 느려진다. top에서 CPU가 5% 근처에 고정되어 있으면 크레딧 소진이다.

원인 3 — 디스크 I/O 병목

Swap이 있는 상태에서 RAM이 부족하면 디스크로 데이터를 밀어내고(swap out) 다시 불러오는(swap in) 작업이 반복된다. Lightsail의 제한된 디스크 성능이 병목이 되어 시스템이 멈춘 것처럼 보일 수 있다.

Swap이 있다고 무조건 안전한 건 아니다. “죽지는 않지만 엄청 느려질 수 있는” 트레이드오프라는 걸 알아두자.

원인 4 — AWS 인프라 자체 이슈

드물지만 리전 장애, 인스턴스 점검, 물리 호스트 마이그레이션으로 인해 접속이 끊기는 경우가 있다. status.aws.amazon.com에서 확인 가능.

뭐가 원인인지 진단하는 법

SSH 접속이 되면 아래 명령어로 확인한다:

# 메모리 및 Swap 사용량
free -h

# CPU, 프로세스별 메모리 실시간 확인
top

# OOM으로 죽은 프로세스 로그
dmesg | grep -i "oom"

# 시스템 로그에서 메모리 관련 에러
journalctl -xe | grep -i "memory\|oom\|killed"

빠른 판단법:
dmesg | grep -i "oom" 결과에 Out of memory: Kill process 있으면 → 메모리 부족
top에서 CPU가 5% 근처에 고정 → 크레딧 소진
– 둘 다 아니면 → 디스크 I/O 또는 AWS 인프라

내 경우엔 dmesg에서 OOM Kill 로그가 바로 나왔다. 메모리 문제 확정.

Swap이 뭔가

RAM이 부족할 때 디스크 일부를 임시 메모리처럼 쓰는 리눅스 기능이다. 책상(RAM)이 가득 찼을 때 서랍(디스크)에 서류를 넣어두는 거라고 보면 된다. 서랍에서 꺼내는 건 느리지만, 서류를 버리는 것(OOM Kill)보다는 낫다.

항목 RAM Swap
속도 매우 빠름 수십 배 느림
용량 고정 (2GB) 디스크 여유만큼 설정
없으면? 메모리 부족 시 프로세스 강제 종료

구성 방식은 파티션 방식과 파일 방식 두 가지인데, 클라우드 환경에선 파일 방식(/swapfile)을 쓴다. 크기 변경이 쉽고 설정이 간단하다.

권장 크기: 2GB RAM이면 Swap 2~4GB. Lightsail 2GB 인스턴스에서는 사실상 필수.

Swap 2GB → 4GB 확장 (내가 한 과정)

# 1. 기존 Swap 끄기
sudo swapoff -a

# 2. 기존 swapfile 삭제
sudo rm /swapfile

# 3. 4GB 새 swapfile 생성
sudo fallocate -l 4G /swapfile
# fallocate가 안 되면: sudo dd if=/dev/zero of=/swapfile bs=1M count=4096

# 4. 권한 설정 (root만 읽기/쓰기)
sudo chmod 600 /swapfile

# 5. Swap 포맷
sudo mkswap /swapfile

# 6. 활성화
sudo swapon /swapfile

# 7. 확인 — Swap이 4.0Gi로 표시되면 성공
free -h

# 8. 재부팅 후에도 유지되도록 등록
cat /etc/fstab | grep swap  # 이미 있는지 확인
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

fallocate는 디스크 공간만 빠르게 예약하는 명령어라 몇 초면 끝난다. dd는 실제로 0을 기록하니까 수십 초 걸린다. 실행 전에 df -h로 디스크 여유를 확인하자. 60GB SSD에서 시스템+앱이 15GB 쓰고 있으면 4GB Swap 만들어도 40GB 이상 남는다.

chmod 600은 필수다. Swap 파일에는 RAM에서 내려온 데이터가 들어가니까 다른 사용자가 읽을 수 있으면 안 된다. 이거 안 하면 insecure permissions 경고가 뜬다.

/etc/fstab은 부팅 시 자동 마운트 목록이다. 여기 안 넣으면 재부팅할 때마다 Swap이 사라진다.

swappiness 튜닝

리눅스가 “RAM이 얼마나 부족해야 Swap을 쓸 건지” 결정하는 값이다.

  • 0: RAM이 거의 다 찬 경우에만 사용
  • 60: 기본값. 꽤 자주 사용
  • 100: 적극적으로 사용

클라우드 서버에서는 10~30 정도가 적당하다. 기본값 60은 너무 자주 Swap을 써서 디스크 I/O 병목을 유발할 수 있다.

# 현재 값 확인
cat /proc/sys/vm/swappiness

# 임시 변경
sudo sysctl vm.swappiness=10

# 영구 변경
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf

나는 10으로 설정했다.

Swap은 응급처치 — 근본 해결은 따로

Swap 확장 후 서버가 안정적으로 돌아가긴 하는데, free -h로 확인해보면 Swap 사용량이 꽤 높다. RAM 자체가 부족하다는 뜻이다.

장기적으로 고려할 것들:

방법 효과 비용
Lightsail 플랜 업그레이드 (2GB→4GB) RAM 2배 월 $7→$14
불필요 서비스 종료 메모리 즉시 확보 무료
Apache MaxRequestWorkers 줄이기 Apache 메모리 절약 무료
MariaDB innodb_buffer_pool_size 축소 DB 메모리 절약 무료
htop 설치해서 정기 모니터링 문제 조기 발견 무료

Lightsail 가성비가 안 맞다 싶으면 Oracle Cloud Free Tier(1GB RAM 인스턴스 2개 무료), DigitalOcean, Vultr 같은 대안도 있다.

나는 일단 Swap 확장 + swappiness 10 + Apache Workers 줄이기로 버티고 있고, 트래픽이 더 늘면 플랜 업그레이드를 할 예정이다.