어느 날 갑자기 서버가 먹통
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 줄이기로 버티고 있고, 트래픽이 더 늘면 플랜 업그레이드를 할 예정이다.


